diff --git a/CHANGELOG.md b/CHANGELOG.md index db0936738..229409646 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,64 @@ # Change-Log -- + New +- + Added - ✓ Fixed - Δ Changed - − Removed +## [Next] + +- [Full commit-log](https://github.com/Schlaefer/Saito/compare/5.6.0...) +- [Download release-zip](https://github.com/Schlaefer/Saito/releases/download//saito-release-master-.zip) + +### Changes + +### Update Notes + +## [5.6.0] + +- [Full commit-log](https://github.com/Schlaefer/Saito/compare/5.5.0...5.6.0) +- [Download release-zip](https://github.com/Schlaefer/Saito/releases/download//saito-release-master-5.6.0.zip) + +### Changes + +- + Adds permission `saito.core.posting.solves.set` for marking a posting as solution/helpful (defaults to thread creator). +- + Improves compatibility with PHP 7.3 +- + Improves browser detection for changes in the Bota theme CSS +- + Improves logging of unauthorized access +- ✓ Deleting a bookmark creates an empty area above the bookmarks +- ✓ User roles with ID greater than 3 can't be assigned to category access control +- ✓ Fixes link to default favicon if installed in subdirectory +- Δ Adds "Saito" prefix to CSRF-cookie name +- Δ Moves layout for viewing a posting and answering from center to the left +- Δ Updates Saito default favicon +- − Removes visiblity description for category in category-title hover +- Search: + - ✓ Internal error on simple search when results are sorted by rank + - ✓ Internal error if search term contains multiple whitespaces +- Improves dark theme: + - ✓ Drop down menus aren't styled + - ✓ Code inserts aren't styled + - Δ Exchanges dark and light distinction between background and form areas + - Δ Darkens border and dividiers +- Uploader: + - + Adds filter options + - + Performance improvements for users with many (100+) uploads + - + Adds permission `saito.plugin.uploader.view` for viewing uploads (defaults to upload owner and group `admin`). + - + Adds permission `saito.plugin.uploader.add` for uploading new files (defaults to profile owner). + - + Adds permission `saito.plugin.uploader.delete` for deleting uploads (defaults to upload owner and group `admin`). + - + Adds "audio/ogg" and "audio/opus" to default allowed mime-types + - ✓ Wrong error message is shown if no file was received on the server + - Δ Layout improvements +- Internal code changes: + - + Minor changes for improved theming support + - Δ Refactors creation, update and validation of postings + - Δ Updates PHP and Javascript libraries + - Δ Entries::Table throws RecordNotFoundException instead of returning null + - Δ Update Apcu version in docker container to 5.1.18 + - Δ Drafts for new threads are stored with a `pid` of `0` instead of `NULL` + - − Removes SaitoValidationProvider::validateAssoc with CakePHP build-in facility + - − Removes abandonded Selenium test files + ## [5.5.0] - 2019-11-16 - [Full commit-log](https://github.com/Schlaefer/Saito/compare/5.4.1...5.5.0) diff --git a/build.xml b/build.xml index 6741aa68d..310e966a6 100644 --- a/build.xml +++ b/build.xml @@ -21,6 +21,7 @@ + diff --git a/composer.json b/composer.json index aee46a4f7..7239c771d 100644 --- a/composer.json +++ b/composer.json @@ -11,6 +11,9 @@ "forum": "http://saito.siezi.com/forum/" } }, + "config": { + "discard-changes": true + }, "require": { "php": ">=7.2", "cakephp/cakephp": "3.8.*", @@ -25,7 +28,7 @@ "markstory/geshi": "^3", "siezi/cakephp-simple-captcha": "*", "yzalis/identicon": "*", - "league/commonmark": "^0.17.5", + "league/commonmark": "^1.0", "suin/php-rss-writer": "^1.6", "friendsofcake/bootstrap-ui": "dev-develop", "friendsofcake/search": "^4.4", @@ -97,10 +100,10 @@ "post-create-project-cmd": "App\\Console\\Installer::postInstall", "post-autoload-dump": "Cake\\Composer\\Installer\\PluginInstaller::postAutoloadDump", - "cs-check": "phpcs --runtime-set ignore_warnings_on_exit true", - "cs-fix": "phpcbf > /dev/null || true", - "php-check": ["@phpstan", "@cs-fix", "@cs-check"], - "phpstan": "vendor/bin/phpstan analyse --ansi", + "cs-check": "unset XDEBUG_CONFIG; phpcs --runtime-set ignore_warnings_on_exit true", + "cs-fix": "unset XDEBUG_CONFIG; phpcbf > /dev/null || true", + "check": ["@cs-fix", "@cs-check"], + "phpstan": "unset XDEBUG_CONFIG; vendor/bin/phpstan analyse --ansi", "coverage": [ "Composer\\Config::disableProcessTimeout", "unset XDEBUG_CONFIG; composer phpunit -- --coverage-html docs/local/" @@ -111,12 +114,12 @@ ], "phpunit": [ "Composer\\Config::disableProcessTimeout", - "phpunit --colors=always" + "unset XDEBUG_CONFIG; phpunit --colors=always" ], "test": [ - "unset XDEBUG_CONFIG", "@phpunit", - "@php-check" + "@phpstan", + "@check" ], "js-all": "yarn run test", diff --git a/composer.lock b/composer.lock index 2194566d1..6bf8c740a 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "99f1b718749b0447db98a4a4a2414566", + "content-hash": "4e308c870760d041f92d42302def387c", "packages": [ { "name": "aura/di", @@ -107,21 +107,21 @@ }, { "name": "cakephp/authentication", - "version": "1.2.1", + "version": "1.4.0", "source": { "type": "git", "url": "https://github.com/cakephp/authentication.git", - "reference": "98dce91a4440f2d3930b200537e3e91eb9bcf149" + "reference": "007d62a91d85556b590187660084286df570daa4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cakephp/authentication/zipball/98dce91a4440f2d3930b200537e3e91eb9bcf149", - "reference": "98dce91a4440f2d3930b200537e3e91eb9bcf149", + "url": "https://api.github.com/repos/cakephp/authentication/zipball/007d62a91d85556b590187660084286df570daa4", + "reference": "007d62a91d85556b590187660084286df570daa4", "shasum": "" }, "require": { "cakephp/core": "^3.7", - "psr/http-message": "~1.0", + "psr/http-message": "^1.0", "zendframework/zend-diactoros": "^1.4.0" }, "require-dev": { @@ -131,7 +131,7 @@ "phpunit/phpunit": "^5.7.14|^6.0" }, "suggest": { - "cakephp/cakephp": "Install version >=3.5.0 to use \"CookieAuthenticator\".", + "cakephp/cakephp": "Install full core to use \"CookieAuthenticator\".", "cakephp/orm": "To use \"OrmResolver\" (Not needed separately if using full CakePHP framework).", "cakephp/utility": "Provides CakePHP security methods. Required for the JWT adapter and Legacy password hasher.", "ext-ldap": "Make sure this php extension is installed and enabled on your system if you want to use the built-in LDAP adapter for \"LdapIdentifier\".", @@ -161,20 +161,20 @@ "cakephp", "middleware" ], - "time": "2019-09-22T15:25:23+00:00" + "time": "2019-11-09T10:51:04+00:00" }, { "name": "cakephp/cakephp", - "version": "3.8.5", + "version": "3.8.6", "source": { "type": "git", "url": "https://github.com/cakephp/cakephp.git", - "reference": "ea64434740f0d2a53438f95a3de414de63a11101" + "reference": "34833a0c02fc1fc21e27ceb69cf7b4f7c131a3cc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cakephp/cakephp/zipball/ea64434740f0d2a53438f95a3de414de63a11101", - "reference": "ea64434740f0d2a53438f95a3de414de63a11101", + "url": "https://api.github.com/repos/cakephp/cakephp/zipball/34833a0c02fc1fc21e27ceb69cf7b4f7c131a3cc", + "reference": "34833a0c02fc1fc21e27ceb69cf7b4f7c131a3cc", "shasum": "" }, "require": { @@ -250,7 +250,7 @@ "rapid-development", "validation" ], - "time": "2019-10-07T00:51:50+00:00" + "time": "2019-11-07T01:11:43+00:00" }, { "name": "cakephp/chronos", @@ -311,16 +311,16 @@ }, { "name": "cakephp/migrations", - "version": "2.3.0", + "version": "2.4.0", "source": { "type": "git", "url": "https://github.com/cakephp/migrations.git", - "reference": "3d1750bb218958b4c48fea1365c619bedea62d69" + "reference": "643e54e627e876c10b5ffa1c706a6819aa6a70b9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cakephp/migrations/zipball/3d1750bb218958b4c48fea1365c619bedea62d69", - "reference": "3d1750bb218958b4c48fea1365c619bedea62d69", + "url": "https://api.github.com/repos/cakephp/migrations/zipball/643e54e627e876c10b5ffa1c706a6819aa6a70b9", + "reference": "643e54e627e876c10b5ffa1c706a6819aa6a70b9", "shasum": "" }, "require": { @@ -360,7 +360,7 @@ "cakephp", "migrations" ], - "time": "2019-10-07T22:04:21+00:00" + "time": "2019-11-10T15:12:59+00:00" }, { "name": "cakephp/plugin-installer", @@ -762,16 +762,16 @@ "source": { "type": "git", "url": "https://github.com/GeSHi/geshi-1.0.git", - "reference": "5861c58981244ab6ee0dd337f096ff14bf15b1eb" + "reference": "fd22ab78481bf90337862b590e6f7517863926b8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/GeSHi/geshi-1.0/zipball/5861c58981244ab6ee0dd337f096ff14bf15b1eb", - "reference": "5861c58981244ab6ee0dd337f096ff14bf15b1eb", + "url": "https://api.github.com/repos/GeSHi/geshi-1.0/zipball/fd22ab78481bf90337862b590e6f7517863926b8", + "reference": "fd22ab78481bf90337862b590e6f7517863926b8", "shasum": "" }, "require-dev": { - "phpunit/phpunit": "^5.7" + "phpunit/phpunit": "^5.7 || ^6.5 || ^7.5 || ^8.2" }, "type": "library", "autoload": { @@ -794,7 +794,7 @@ ], "description": "Generic Syntax Highlighter", "homepage": "http://qbnz.com/highlighter/", - "time": "2018-10-01T23:49:06+00:00" + "time": "2019-10-20T20:54:46+00:00" }, { "name": "guzzlehttp/psr7", @@ -869,16 +869,16 @@ }, { "name": "intervention/image", - "version": "2.5.0", + "version": "2.5.1", "source": { "type": "git", "url": "https://github.com/Intervention/image.git", - "reference": "39eaef720d082ecc54c64bf54541c55f10db546d" + "reference": "abbf18d5ab8367f96b3205ca3c89fb2fa598c69e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Intervention/image/zipball/39eaef720d082ecc54c64bf54541c55f10db546d", - "reference": "39eaef720d082ecc54c64bf54541c55f10db546d", + "url": "https://api.github.com/repos/Intervention/image/zipball/abbf18d5ab8367f96b3205ca3c89fb2fa598c69e", + "reference": "abbf18d5ab8367f96b3205ca3c89fb2fa598c69e", "shasum": "" }, "require": { @@ -935,7 +935,7 @@ "thumbnail", "watermark" ], - "time": "2019-06-24T14:06:31+00:00" + "time": "2019-11-02T09:15:47+00:00" }, { "name": "jbbcode/jbbcode", @@ -1239,34 +1239,36 @@ }, { "name": "league/commonmark", - "version": "0.17.5", + "version": "1.1.1", "source": { "type": "git", "url": "https://github.com/thephpleague/commonmark.git", - "reference": "82d7ab62d7f68391cb9d323f3ccce50be24a5369" + "reference": "d74654d85954e3b9451d67faaebacd210fc70252" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/82d7ab62d7f68391cb9d323f3ccce50be24a5369", - "reference": "82d7ab62d7f68391cb9d323f3ccce50be24a5369", + "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/d74654d85954e3b9451d67faaebacd210fc70252", + "reference": "d74654d85954e3b9451d67faaebacd210fc70252", "shasum": "" }, "require": { "ext-mbstring": "*", - "php": ">=5.6.5" + "php": "^7.1" }, "replace": { "colinodell/commonmark-php": "*" }, "require-dev": { "cebe/markdown": "~1.0", - "commonmark/commonmark.js": "0.28", + "commonmark/commonmark.js": "0.29.0", "erusev/parsedown": "~1.0", + "ext-json": "*", "michelf/php-markdown": "~1.4", - "mikehaertl/php-shellcommand": "^1.2", - "phpunit/phpunit": "^5.7|^6.5", - "scrutinizer/ocular": "^1.1", - "symfony/finder": "^3.0|^4.0" + "mikehaertl/php-shellcommand": "^1.4", + "phpstan/phpstan-shim": "^0.11.5", + "phpunit/phpunit": "^7.5", + "scrutinizer/ocular": "^1.5", + "symfony/finder": "^4.2" }, "suggest": { "league/commonmark-extras": "Library of useful extensions including smart punctuation" @@ -1277,12 +1279,12 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "0.18-dev" + "dev-master": "1.2-dev" } }, "autoload": { "psr-4": { - "League\\CommonMark\\": "src/" + "League\\CommonMark\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -1297,14 +1299,14 @@ "role": "Lead Developer" } ], - "description": "Markdown parser for PHP based on the CommonMark spec", - "homepage": "https://github.com/thephpleague/commonmark", + "description": "PHP Markdown parser based on the CommonMark spec", + "homepage": "https://commonmark.thephpleague.com", "keywords": [ "commonmark", "markdown", "parser" ], - "time": "2018-03-29T14:35:19+00:00" + "time": "2019-11-11T22:23:29+00:00" }, { "name": "m1/env", @@ -1566,16 +1568,16 @@ }, { "name": "psr/log", - "version": "1.1.0", + "version": "1.1.2", "source": { "type": "git", "url": "https://github.com/php-fig/log.git", - "reference": "6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd" + "reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd", - "reference": "6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd", + "url": "https://api.github.com/repos/php-fig/log/zipball/446d54b4cb6bf489fc9d75f55843658e6f25d801", + "reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801", "shasum": "" }, "require": { @@ -1584,7 +1586,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "1.1.x-dev" } }, "autoload": { @@ -1609,7 +1611,7 @@ "psr", "psr-3" ], - "time": "2018-11-20T15:27:04+00:00" + "time": "2019-11-01T11:05:21+00:00" }, { "name": "psr/simple-cache", @@ -1868,16 +1870,16 @@ }, { "name": "symfony/config", - "version": "v4.3.5", + "version": "v4.3.8", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "0acb26407a9e1a64a275142f0ae5e36436342720" + "reference": "8267214841c44d315a55242ea867684eb43c42ce" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/0acb26407a9e1a64a275142f0ae5e36436342720", - "reference": "0acb26407a9e1a64a275142f0ae5e36436342720", + "url": "https://api.github.com/repos/symfony/config/zipball/8267214841c44d315a55242ea867684eb43c42ce", + "reference": "8267214841c44d315a55242ea867684eb43c42ce", "shasum": "" }, "require": { @@ -1928,20 +1930,20 @@ ], "description": "Symfony Config Component", "homepage": "https://symfony.com", - "time": "2019-09-19T15:51:53+00:00" + "time": "2019-11-08T08:31:27+00:00" }, { "name": "symfony/console", - "version": "v4.3.5", + "version": "v4.3.8", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "929ddf360d401b958f611d44e726094ab46a7369" + "reference": "831424efae0a1fe6642784bd52aae14ece6538e6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/929ddf360d401b958f611d44e726094ab46a7369", - "reference": "929ddf360d401b958f611d44e726094ab46a7369", + "url": "https://api.github.com/repos/symfony/console/zipball/831424efae0a1fe6642784bd52aae14ece6538e6", + "reference": "831424efae0a1fe6642784bd52aae14ece6538e6", "shasum": "" }, "require": { @@ -2003,11 +2005,11 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2019-10-07T12:36:49+00:00" + "time": "2019-11-13T07:29:07+00:00" }, { "name": "symfony/filesystem", - "version": "v4.3.5", + "version": "v4.3.8", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", @@ -2349,16 +2351,16 @@ }, { "name": "symfony/service-contracts", - "version": "v1.1.7", + "version": "v1.1.8", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "ffcde9615dc5bb4825b9f6aed07716f1f57faae0" + "reference": "ffc7f5692092df31515df2a5ecf3b7302b3ddacf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/ffcde9615dc5bb4825b9f6aed07716f1f57faae0", - "reference": "ffcde9615dc5bb4825b9f6aed07716f1f57faae0", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/ffc7f5692092df31515df2a5ecf3b7302b3ddacf", + "reference": "ffc7f5692092df31515df2a5ecf3b7302b3ddacf", "shasum": "" }, "require": { @@ -2403,20 +2405,20 @@ "interoperability", "standards" ], - "time": "2019-09-17T11:12:18+00:00" + "time": "2019-10-14T12:27:06+00:00" }, { "name": "symfony/yaml", - "version": "v4.3.5", + "version": "v4.3.8", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "41e16350a2a1c7383c4735aa2f9fce74cf3d1178" + "reference": "324cf4b19c345465fad14f3602050519e09e361d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/41e16350a2a1c7383c4735aa2f9fce74cf3d1178", - "reference": "41e16350a2a1c7383c4735aa2f9fce74cf3d1178", + "url": "https://api.github.com/repos/symfony/yaml/zipball/324cf4b19c345465fad14f3602050519e09e361d", + "reference": "324cf4b19c345465fad14f3602050519e09e361d", "shasum": "" }, "require": { @@ -2462,7 +2464,7 @@ ], "description": "Symfony Yaml Component", "homepage": "https://symfony.com", - "time": "2019-09-11T15:41:19+00:00" + "time": "2019-10-30T12:58:49+00:00" }, { "name": "yzalis/identicon", @@ -2846,16 +2848,16 @@ }, { "name": "cakephp/debug_kit", - "version": "3.20.3", + "version": "3.21.0", "source": { "type": "git", "url": "https://github.com/cakephp/debug_kit.git", - "reference": "2ebc6b61fdb4741e890c564ab4d55a9b1d29c47f" + "reference": "74c289cbd9ee07a531ce813dec744c9f2f472e14" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cakephp/debug_kit/zipball/2ebc6b61fdb4741e890c564ab4d55a9b1d29c47f", - "reference": "2ebc6b61fdb4741e890c564ab4d55a9b1d29c47f", + "url": "https://api.github.com/repos/cakephp/debug_kit/zipball/74c289cbd9ee07a531ce813dec744c9f2f472e14", + "reference": "74c289cbd9ee07a531ce813dec744c9f2f472e14", "shasum": "" }, "require": { @@ -2876,8 +2878,8 @@ "type": "cakephp-plugin", "autoload": { "psr-4": { - "DebugKit\\": "src", - "DebugKit\\Test\\Fixture\\": "tests\\Fixture" + "DebugKit\\": "src/", + "DebugKit\\Test\\Fixture\\": "tests/Fixture/" } }, "notification-url": "https://packagist.org/downloads/", @@ -2887,7 +2889,7 @@ "authors": [ { "name": "Mark Story", - "homepage": "http://mark-story.com", + "homepage": "https://mark-story.com", "role": "Author" }, { @@ -2902,20 +2904,20 @@ "debug", "kit" ], - "time": "2019-10-09T01:55:34+00:00" + "time": "2019-11-10T02:41:02+00:00" }, { "name": "composer/composer", - "version": "1.9.0", + "version": "1.9.1", "source": { "type": "git", "url": "https://github.com/composer/composer.git", - "reference": "314aa57fdcfc942065996f59fb73a8b3f74f3fa5" + "reference": "bb01f2180df87ce7992b8331a68904f80439dd2f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/composer/zipball/314aa57fdcfc942065996f59fb73a8b3f74f3fa5", - "reference": "314aa57fdcfc942065996f59fb73a8b3f74f3fa5", + "url": "https://api.github.com/repos/composer/composer/zipball/bb01f2180df87ce7992b8331a68904f80439dd2f", + "reference": "bb01f2180df87ce7992b8331a68904f80439dd2f", "shasum": "" }, "require": { @@ -2982,7 +2984,7 @@ "dependency", "package" ], - "time": "2019-08-02T18:55:33+00:00" + "time": "2019-11-01T16:20:17+00:00" }, { "name": "composer/semver", @@ -3108,24 +3110,24 @@ }, { "name": "composer/xdebug-handler", - "version": "1.3.3", + "version": "1.4.0", "source": { "type": "git", "url": "https://github.com/composer/xdebug-handler.git", - "reference": "46867cbf8ca9fb8d60c506895449eb799db1184f" + "reference": "cbe23383749496fe0f373345208b79568e4bc248" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/46867cbf8ca9fb8d60c506895449eb799db1184f", - "reference": "46867cbf8ca9fb8d60c506895449eb799db1184f", + "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/cbe23383749496fe0f373345208b79568e4bc248", + "reference": "cbe23383749496fe0f373345208b79568e4bc248", "shasum": "" }, "require": { - "php": "^5.3.2 || ^7.0", + "php": "^5.3.2 || ^7.0 || ^8.0", "psr/log": "^1.0" }, "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5" + "phpunit/phpunit": "^4.8.35 || ^5.7 || 6.5 - 8" }, "type": "library", "autoload": { @@ -3143,12 +3145,12 @@ "email": "john-stevenson@blueyonder.co.uk" } ], - "description": "Restarts a process without xdebug.", + "description": "Restarts a process without Xdebug.", "keywords": [ "Xdebug", "performance" ], - "time": "2019-05-27T17:52:04+00:00" + "time": "2019-11-06T16:40:04+00:00" }, { "name": "dnoegel/php-xdg-base-dir", @@ -3185,16 +3187,16 @@ }, { "name": "doctrine/instantiator", - "version": "1.2.0", + "version": "1.3.0", "source": { "type": "git", "url": "https://github.com/doctrine/instantiator.git", - "reference": "a2c590166b2133a4633738648b6b064edae0814a" + "reference": "ae466f726242e637cebdd526a7d991b9433bacf1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/a2c590166b2133a4633738648b6b064edae0814a", - "reference": "a2c590166b2133a4633738648b6b064edae0814a", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/ae466f726242e637cebdd526a7d991b9433bacf1", + "reference": "ae466f726242e637cebdd526a7d991b9433bacf1", "shasum": "" }, "require": { @@ -3237,7 +3239,7 @@ "constructor", "instantiate" ], - "time": "2019-03-17T17:37:11+00:00" + "time": "2019-10-21T16:45:58+00:00" }, { "name": "jakub-onderka/php-console-color", @@ -3490,23 +3492,23 @@ }, { "name": "justinrainbow/json-schema", - "version": "5.2.8", + "version": "5.2.9", "source": { "type": "git", "url": "https://github.com/justinrainbow/json-schema.git", - "reference": "dcb6e1006bb5fd1e392b4daa68932880f37550d4" + "reference": "44c6787311242a979fa15c704327c20e7221a0e4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/dcb6e1006bb5fd1e392b4daa68932880f37550d4", - "reference": "dcb6e1006bb5fd1e392b4daa68932880f37550d4", + "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/44c6787311242a979fa15c704327c20e7221a0e4", + "reference": "44c6787311242a979fa15c704327c20e7221a0e4", "shasum": "" }, "require": { "php": ">=5.3.3" }, "require-dev": { - "friendsofphp/php-cs-fixer": "~2.2.20", + "friendsofphp/php-cs-fixer": "~2.2.20||~2.15.1", "json-schema/json-schema-test-suite": "1.2.0", "phpunit/phpunit": "^4.8.35" }, @@ -3552,7 +3554,7 @@ "json", "schema" ], - "time": "2019-01-14T23:55:14+00:00" + "time": "2019-09-25T14:49:45+00:00" }, { "name": "myclabs/deep-copy", @@ -3604,16 +3606,16 @@ }, { "name": "nette/bootstrap", - "version": "v3.0.0", + "version": "v3.0.1", "source": { "type": "git", "url": "https://github.com/nette/bootstrap.git", - "reference": "e1075af05c211915e03e0c86542f3ba5433df4a3" + "reference": "b45a1e33b6a44beb307756522396551e5a9ff249" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nette/bootstrap/zipball/e1075af05c211915e03e0c86542f3ba5433df4a3", - "reference": "e1075af05c211915e03e0c86542f3ba5433df4a3", + "url": "https://api.github.com/repos/nette/bootstrap/zipball/b45a1e33b6a44beb307756522396551e5a9ff249", + "reference": "b45a1e33b6a44beb307756522396551e5a9ff249", "shasum": "" }, "require": { @@ -3621,6 +3623,9 @@ "nette/utils": "^3.0", "php": ">=7.1" }, + "conflict": { + "tracy/tracy": "<2.6" + }, "require-dev": { "latte/latte": "^2.2", "nette/application": "^3.0", @@ -3673,7 +3678,7 @@ "configurator", "nette" ], - "time": "2019-03-26T12:59:07+00:00" + "time": "2019-09-30T08:19:38+00:00" }, { "name": "nette/di", @@ -3994,16 +3999,16 @@ }, { "name": "nette/schema", - "version": "v1.0.0", + "version": "v1.0.1", "source": { "type": "git", "url": "https://github.com/nette/schema.git", - "reference": "6241d8d4da39e825dd6cb5bfbe4242912f4d7e4d" + "reference": "337117df1dade22e2ba1fdc4a4b832c1e9b06b76" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nette/schema/zipball/6241d8d4da39e825dd6cb5bfbe4242912f4d7e4d", - "reference": "6241d8d4da39e825dd6cb5bfbe4242912f4d7e4d", + "url": "https://api.github.com/repos/nette/schema/zipball/337117df1dade22e2ba1fdc4a4b832c1e9b06b76", + "reference": "337117df1dade22e2ba1fdc4a4b832c1e9b06b76", "shasum": "" }, "require": { @@ -4047,20 +4052,20 @@ "config", "nette" ], - "time": "2019-04-03T15:53:25+00:00" + "time": "2019-10-31T20:52:19+00:00" }, { "name": "nette/utils", - "version": "v3.0.1", + "version": "v3.0.2", "source": { "type": "git", "url": "https://github.com/nette/utils.git", - "reference": "bd961f49b211997202bda1d0fbc410905be370d4" + "reference": "c133e18c922dcf3ad07673077d92d92cef25a148" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nette/utils/zipball/bd961f49b211997202bda1d0fbc410905be370d4", - "reference": "bd961f49b211997202bda1d0fbc410905be370d4", + "url": "https://api.github.com/repos/nette/utils/zipball/c133e18c922dcf3ad07673077d92d92cef25a148", + "reference": "c133e18c922dcf3ad07673077d92d92cef25a148", "shasum": "" }, "require": { @@ -4076,6 +4081,7 @@ "ext-intl": "to use Strings::webalize(), toAscii(), normalize() and compare()", "ext-json": "to use Nette\\Utils\\Json", "ext-mbstring": "to use Strings::lower() etc...", + "ext-tokenizer": "to use Nette\\Utils\\Reflection::getUseStatements()", "ext-xml": "to use Strings::length() etc. when mbstring is not available" }, "type": "library", @@ -4123,20 +4129,20 @@ "utility", "validation" ], - "time": "2019-03-22T01:00:30+00:00" + "time": "2019-10-21T20:40:16+00:00" }, { "name": "nikic/php-parser", - "version": "v4.2.4", + "version": "v4.3.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "97e59c7a16464196a8b9c77c47df68e4a39a45c4" + "reference": "9a9981c347c5c49d6dfe5cf826bb882b824080dc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/97e59c7a16464196a8b9c77c47df68e4a39a45c4", - "reference": "97e59c7a16464196a8b9c77c47df68e4a39a45c4", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/9a9981c347c5c49d6dfe5cf826bb882b824080dc", + "reference": "9a9981c347c5c49d6dfe5cf826bb882b824080dc", "shasum": "" }, "require": { @@ -4144,6 +4150,7 @@ "php": ">=7.0" }, "require-dev": { + "ircmaxell/php-yacc": "0.0.5", "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0" }, "bin": [ @@ -4152,7 +4159,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } }, "autoload": { @@ -4174,20 +4181,20 @@ "parser", "php" ], - "time": "2019-09-01T07:51:21+00:00" + "time": "2019-11-08T13:50:10+00:00" }, { "name": "ocramius/package-versions", - "version": "1.4.0", + "version": "1.4.2", "source": { "type": "git", "url": "https://github.com/Ocramius/PackageVersions.git", - "reference": "a4d4b60d0e60da2487bd21a2c6ac089f85570dbb" + "reference": "44af6f3a2e2e04f2af46bcb302ad9600cba41c7d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Ocramius/PackageVersions/zipball/a4d4b60d0e60da2487bd21a2c6ac089f85570dbb", - "reference": "a4d4b60d0e60da2487bd21a2c6ac089f85570dbb", + "url": "https://api.github.com/repos/Ocramius/PackageVersions/zipball/44af6f3a2e2e04f2af46bcb302ad9600cba41c7d", + "reference": "44af6f3a2e2e04f2af46bcb302ad9600cba41c7d", "shasum": "" }, "require": { @@ -4199,7 +4206,7 @@ "doctrine/coding-standard": "^5.0.1", "ext-zip": "*", "infection/infection": "^0.7.1", - "phpunit/phpunit": "^7.0.0" + "phpunit/phpunit": "^7.5.17" }, "type": "composer-plugin", "extra": { @@ -4224,7 +4231,7 @@ } ], "description": "Composer plugin that provides efficient querying for installed package versions (no runtime IO)", - "time": "2019-02-21T12:16:21+00:00" + "time": "2019-11-15T16:17:10+00:00" }, { "name": "phar-io/manifest", @@ -4683,16 +4690,16 @@ }, { "name": "phpstan/phpstan", - "version": "0.11.16", + "version": "0.11.19", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "635cf20f3b92ce34ee94a8d2f282d62eb9dc6e1b" + "reference": "63cc502f6957b7f74efbac444b4cf219dcadffd7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/635cf20f3b92ce34ee94a8d2f282d62eb9dc6e1b", - "reference": "635cf20f3b92ce34ee94a8d2f282d62eb9dc6e1b", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/63cc502f6957b7f74efbac444b4cf219dcadffd7", + "reference": "63cc502f6957b7f74efbac444b4cf219dcadffd7", "shasum": "" }, "require": { @@ -4700,6 +4707,7 @@ "jean85/pretty-package-versions": "^1.0.3", "nette/bootstrap": "^2.4 || ^3.0", "nette/di": "^2.4.7 || ^3.0", + "nette/neon": "^2.4.3 || ^3.0", "nette/robot-loader": "^3.0.1", "nette/schema": "^1.0", "nette/utils": "^2.4.5 || ^3.0", @@ -4753,7 +4761,7 @@ "MIT" ], "description": "PHPStan - PHP Static Analysis Tool", - "time": "2019-09-17T11:19:51+00:00" + "time": "2019-10-22T20:20:22+00:00" }, { "name": "phpunit/php-code-coverage", @@ -5783,16 +5791,16 @@ }, { "name": "seld/jsonlint", - "version": "1.7.1", + "version": "1.7.2", "source": { "type": "git", "url": "https://github.com/Seldaek/jsonlint.git", - "reference": "d15f59a67ff805a44c50ea0516d2341740f81a38" + "reference": "e2e5d290e4d2a4f0eb449f510071392e00e10d19" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/d15f59a67ff805a44c50ea0516d2341740f81a38", - "reference": "d15f59a67ff805a44c50ea0516d2341740f81a38", + "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/e2e5d290e4d2a4f0eb449f510071392e00e10d19", + "reference": "e2e5d290e4d2a4f0eb449f510071392e00e10d19", "shasum": "" }, "require": { @@ -5828,7 +5836,7 @@ "parser", "validator" ], - "time": "2018-01-24T12:46:19+00:00" + "time": "2019-10-24T14:27:39+00:00" }, { "name": "seld/phar-utils", @@ -5876,16 +5884,16 @@ }, { "name": "squizlabs/php_codesniffer", - "version": "3.5.0", + "version": "3.5.2", "source": { "type": "git", "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", - "reference": "0afebf16a2e7f1e434920fa976253576151effe9" + "reference": "65b12cdeaaa6cd276d4c3033a95b9b88b12701e7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/0afebf16a2e7f1e434920fa976253576151effe9", - "reference": "0afebf16a2e7f1e434920fa976253576151effe9", + "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/65b12cdeaaa6cd276d4c3033a95b9b88b12701e7", + "reference": "65b12cdeaaa6cd276d4c3033a95b9b88b12701e7", "shasum": "" }, "require": { @@ -5923,11 +5931,11 @@ "phpcs", "standards" ], - "time": "2019-09-26T23:12:26+00:00" + "time": "2019-10-28T04:36:32+00:00" }, { "name": "symfony/css-selector", - "version": "v4.3.5", + "version": "v4.3.8", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", @@ -5980,16 +5988,16 @@ }, { "name": "symfony/dom-crawler", - "version": "v4.3.5", + "version": "v4.3.8", "source": { "type": "git", "url": "https://github.com/symfony/dom-crawler.git", - "reference": "e9f7b4d19d69b133bd638eeddcdc757723b4211f" + "reference": "4b9efd5708c3a38593e19b6a33e40867f4f89d72" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/e9f7b4d19d69b133bd638eeddcdc757723b4211f", - "reference": "e9f7b4d19d69b133bd638eeddcdc757723b4211f", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/4b9efd5708c3a38593e19b6a33e40867f4f89d72", + "reference": "4b9efd5708c3a38593e19b6a33e40867f4f89d72", "shasum": "" }, "require": { @@ -6037,20 +6045,20 @@ ], "description": "Symfony DomCrawler Component", "homepage": "https://symfony.com", - "time": "2019-09-28T21:25:05+00:00" + "time": "2019-10-28T17:07:32+00:00" }, { "name": "symfony/finder", - "version": "v4.3.5", + "version": "v4.3.8", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "5e575faa95548d0586f6bedaeabec259714e44d1" + "reference": "72a068f77e317ae77c0a0495236ad292cfb5ce6f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/5e575faa95548d0586f6bedaeabec259714e44d1", - "reference": "5e575faa95548d0586f6bedaeabec259714e44d1", + "url": "https://api.github.com/repos/symfony/finder/zipball/72a068f77e317ae77c0a0495236ad292cfb5ce6f", + "reference": "72a068f77e317ae77c0a0495236ad292cfb5ce6f", "shasum": "" }, "require": { @@ -6086,20 +6094,20 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "time": "2019-09-16T11:29:48+00:00" + "time": "2019-10-30T12:53:54+00:00" }, { "name": "symfony/process", - "version": "v4.3.5", + "version": "v4.3.8", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "50556892f3cc47d4200bfd1075314139c4c9ff4b" + "reference": "3b2e0cb029afbb0395034509291f21191d1a4db0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/50556892f3cc47d4200bfd1075314139c4c9ff4b", - "reference": "50556892f3cc47d4200bfd1075314139c4c9ff4b", + "url": "https://api.github.com/repos/symfony/process/zipball/3b2e0cb029afbb0395034509291f21191d1a4db0", + "reference": "3b2e0cb029afbb0395034509291f21191d1a4db0", "shasum": "" }, "require": { @@ -6135,20 +6143,20 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", - "time": "2019-09-26T21:17:10+00:00" + "time": "2019-10-28T17:07:32+00:00" }, { "name": "symfony/var-dumper", - "version": "v4.3.5", + "version": "v4.3.8", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "bde8957fc415fdc6964f33916a3755737744ff05" + "reference": "ea4940845535c85ff5c505e13b3205b0076d07bf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/bde8957fc415fdc6964f33916a3755737744ff05", - "reference": "bde8957fc415fdc6964f33916a3755737744ff05", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/ea4940845535c85ff5c505e13b3205b0076d07bf", + "reference": "ea4940845535c85ff5c505e13b3205b0076d07bf", "shasum": "" }, "require": { @@ -6211,7 +6219,7 @@ "debug", "dump" ], - "time": "2019-10-04T19:48:13+00:00" + "time": "2019-10-13T12:02:04+00:00" }, { "name": "theseer/tokenizer", @@ -6255,16 +6263,16 @@ }, { "name": "twig/twig", - "version": "v1.42.3", + "version": "v1.42.4", "source": { "type": "git", "url": "https://github.com/twigphp/Twig.git", - "reference": "201baee843e0ffe8b0b956f336dd42b2a92fae4e" + "reference": "e587180584c3d2d6cb864a0454e777bb6dcb6152" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/201baee843e0ffe8b0b956f336dd42b2a92fae4e", - "reference": "201baee843e0ffe8b0b956f336dd42b2a92fae4e", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/e587180584c3d2d6cb864a0454e777bb6dcb6152", + "reference": "e587180584c3d2d6cb864a0454e777bb6dcb6152", "shasum": "" }, "require": { @@ -6317,7 +6325,7 @@ "keywords": [ "templating" ], - "time": "2019-08-24T12:51:03+00:00" + "time": "2019-11-11T16:49:32+00:00" }, { "name": "umpirsky/twig-php-function", diff --git a/config/Migrations/20191231081631_Saito5x6x0.php b/config/Migrations/20191231081631_Saito5x6x0.php new file mode 100755 index 000000000..b3ce25002 --- /dev/null +++ b/config/Migrations/20191231081631_Saito5x6x0.php @@ -0,0 +1,33 @@ +execute('UPDATE drafts SET pid=0 WHERE pid IS NULL'); + $this->table('drafts') + ->changeColumn('pid', 'integer', [ + 'default' => null, + 'limit' => 11, + 'null' => false, + ]) + ->update(); + } + + public function down() + { + + $this->table('drafts') + ->changeColumn('pid', 'integer', [ + 'default' => null, + 'length' => 11, + 'null' => true, + ]) + ->update(); + $this->execute('UPDATE drafts SET pid=NULL WHERE pid=0'); + } +} + diff --git a/config/geshi.php b/config/geshi.php index bbe293106..addb7bb59 100644 --- a/config/geshi.php +++ b/config/geshi.php @@ -1,11 +1,13 @@ set_header_type(GESHI_HEADER_DIV); $geshi->enable_line_numbers(GESHI_FANCY_LINE_NUMBERS, 2); -$geshi->set_line_style('background: white;'); +$geshi->set_line_style('background: #f0fcef;'); // $geshi->enable_classes(); $geshi->set_tab_width(2); $geshi->set_code_style('line-height: inherit;', true); diff --git a/config/permissions.php b/config/permissions.php index 4b7d74fda..514f84389 100644 --- a/config/permissions.php +++ b/config/permissions.php @@ -36,9 +36,9 @@ * everbody > owner > role */ $config['Saito']['Permission']['Resources'] = (new Resources()) - /** - * Allow roles access to resource based on roles - */ + /*********************************************************** + * Core * + ***********************************************************/ // Access to the administration backend ->add((new Resource('saito.core.admin.backend')) ->allow((new ResourceAC())->asRole('admin'))) @@ -63,6 +63,9 @@ // Merge postings ->add((new Resource('saito.core.posting.merge')) ->allow((new ResourceAC())->asRole('mod'))) + // Allow posting to be marked as solution + ->add((new Resource('saito.core.posting.solves.set')) + ->allow((new ResourceAC())->onOwn())) // Show a user's activation status ->add((new Resource('saito.core.user.activate.view')) ->allow((new ResourceAC())->asRole('admin'))) @@ -96,6 +99,9 @@ ->add((new Resource('saito.core.user.password.set')) ->allow((new ResourceAC())->asRole('admin')->onRoles('mod', 'user')) ->allow((new ResourceAC())->asRole('owner'))) + // Use the register form + ->add((new Resource('saito.core.user.register')) + ->allow((new ResourceAC())->asEverybody())) // Change a user's role. Allowed ranks: all the current user has but not // their own rank. ->add((new Resource('saito.core.user.role.set.restricted')) @@ -104,12 +110,28 @@ // their own rank. ->add((new Resource('saito.core.user.role.set.unrestricted')) ->allow((new ResourceAC())->asRole('owner'))) + + /*********************************************************** + * Bookmarks * + ***********************************************************/ // Deleting bookmarks ->add((new Resource('saito.plugin.bookmarks.delete')) ->allow((new ResourceAC())->onOwn())) - // Use the register form - ->add((new Resource('saito.core.user.register')) - ->allow((new ResourceAC())->asEverybody())) + + /*********************************************************** + * Uploader * + ***********************************************************/ + // Allow uploads + ->add((new Resource('saito.plugin.uploader.add')) + ->allow((new ResourceAC())->onOwn())) + // Allow deleting uploads + ->add((new Resource('saito.plugin.uploader.delete')) + ->allow((new ResourceAC())->asRole('admin')) + ->allow((new ResourceAC())->onOwn())) + // View the uploader + ->add((new Resource('saito.plugin.uploader.view')) + ->allow((new ResourceAC())->asRole('admin')) + ->allow((new ResourceAC())->onOwn())) ; return $config; diff --git a/config/saito_config.php b/config/saito_config.php index de9452b61..75b741cef 100644 --- a/config/saito_config.php +++ b/config/saito_config.php @@ -117,9 +117,11 @@ */ ->addType('audio/mpeg') ->addType('audio/mp4') + ->addType('audio/ogg') + ->addType('audio/opus') ->addType('audio/webm') ->addType('image/jpeg', '19MB') - ->addType('image/png', '19MB') + ->addType('image/png', '19MB') ->addType('image/svg+xml') ->addType('text/plain') ->addType('video/mp4') diff --git a/dev/docker/php7/apache/Dockerfile b/dev/docker/php7/apache/Dockerfile index 4d4494cf6..20c9a510c 100644 --- a/dev/docker/php7/apache/Dockerfile +++ b/dev/docker/php7/apache/Dockerfile @@ -33,8 +33,9 @@ RUN docker-php-ext-configure pdo_mysql --with-pdo-mysql=mysqlnd \ opcache # Install apcu -RUN pecl install apcu-5.1.17 +RUN pecl install apcu-5.1.18 RUN docker-php-ext-enable apcu +RUN echo "apc.enable_cli=1" >> /usr/local/etc/php/conf.d/docker-php-ext-apcu.ini # Install xdebug RUN pecl install xdebug-2.7.1 diff --git a/docs/customizing.md b/docs/customizing.md new file mode 100644 index 000000000..6e1f12e65 --- /dev/null +++ b/docs/customizing.md @@ -0,0 +1,40 @@ + +# Customizing # + +## Themes ## + +The default theme *Bota* is implemented as a [CakePHP 3 theme plugin](https://book.cakephp.org/3.0/en/views/themes.html) and lives in *plugins/Bota*. The UI is implemented as [Bootstrap 4](https://getbootstrap.com/docs/4.3/getting-started/introduction/) theme. + +To start your own theme I recommend using SASS and referencing and customizing the default theme. + +Duplicate the *Bota* plugin folder and rename it to *YourTheme*. + +Activate *YourTheme* by setting it as default theme in *config/saito_config.php*. + +Replace everything *plugins/YourTheme/webroot/css/theme.scss* with: + +``` +@import "../../../../../plugins/Bota/webroot/css/src/theme"; +``` + +This include Bota's *theme.scss*. Compiling it with SASS should give you the same look as the default theme. Now customize the theme: + +``` +/// Configure Bootstrap and Saito theme-variables before importing the theme. +$body-color: #222; +... + +/// Import the default theme. +@import "../../../../../plugins/Bota/webroot/css/src/theme"; + +/// Additional customizations +body {...} +... +``` + +Theming resources: + +- [Bootstrap theming](https://getbootstrap.com/docs/4.3/getting-started/theming/) +- [Boostrap variables](https://github.com/twbs/bootstrap/blob/v4.3.0/scss/_variables.scss) +- [SASS documentation](https://sass-lang.com/documentation) +- [Simple GUI crossplatform SASS processor](https://scout-app.io/) diff --git a/frontend/src/app/app.ts b/frontend/src/app/app.ts index 198f8f4f3..cf70b78c0 100644 --- a/frontend/src/app/app.ts +++ b/frontend/src/app/app.ts @@ -16,7 +16,9 @@ import moment from 'moment'; /// Load numeral.js import numeral from 'numeral'; // load locales for numeral.js -require('numeral/locales') +/* tslint:disable */ +require('numeral/locales'); +/* tslint:enable */ interface ISaitoCallbacks { beforeAppInit: CallableFunction[]; diff --git a/frontend/src/locale/de.po b/frontend/src/locale/de.po index df48c3633..c3ec10fcb 100644 --- a/frontend/src/locale/de.po +++ b/frontend/src/locale/de.po @@ -52,23 +52,23 @@ msgid "answer.subject.t" msgstr "Betreff" #: frontend/src/modules/answering/answering.ts:109 -#: frontend/src/modules/answering/answering.ts:304 +#: frontend/src/modules/answering/answering.ts:305 msgid "answer.submit.e.t" msgstr "Fehler: Beitrag wurde nicht gesichert" #: frontend/src/modules/answering/answering.ts:109 -#: frontend/src/modules/answering/answering.ts:261 -#: frontend/src/modules/answering/answering.ts:303 +#: frontend/src/modules/answering/answering.ts:262 +#: frontend/src/modules/answering/answering.ts:304 msgid "api.generic.e.exp" msgstr "Es konnte keine Verbindung zum Internet-Server hergestellt werden." #: frontend/src/modules/answering/answering.ts:109 -#: frontend/src/modules/answering/answering.ts:262 +#: frontend/src/modules/answering/answering.ts:263 msgid "api.generic.e.t" msgstr "Fehler: Keine Verbindung zum Server" #: frontend/src/modules/bookmarks/views/bookmarkItemVw.ts:23 -#: frontend/src/modules/bookmarks/views/bookmarkItemVw.ts:88 +#: frontend/src/modules/bookmarks/views/bookmarkItemVw.ts:90 msgid "bkm.delete.failure" msgstr "Fehler: Lesezeichen konnte nicht gelöscht werden." @@ -166,8 +166,8 @@ msgstr "Abbrechen" msgid "posting.delete.title" msgstr "Beitrag löschen" -#: frontend/src/views/postingActionSolves.ts:22 -#: frontend/src/views/postingActionSolves.ts:33 +#: frontend/src/views/postingActionSolves.ts:23 +#: frontend/src/views/postingActionSolves.ts:34 msgid "posting.helpful" msgstr "Beitrag als hilfreich markieren." @@ -206,55 +206,90 @@ msgstr "Größe" msgid "upl.add.speed.t" msgstr "Geschwindigkeit" -#: frontend/src/modules/uploader/templates/uploaderAddTpl.html:12 -#: frontend/src/modules/uploader/templates/uploaderAddTpl.html:13 +#: frontend/src/modules/uploader/templates/uploaderAddTpl.html:10 +#: frontend/src/modules/uploader/templates/uploaderAddTpl.html:11 msgid "upl.btn.abort.title" msgstr "Abbrechen" -#: frontend/src/modules/answering/editor/MenuButton/MenuButtonUploadView.ts:25 +#: frontend/src/modules/answering/editor/MenuButton/MenuButtonUploadView.ts:23 msgid "upl.btn.insert" msgstr "Einfügen" -#: frontend/src/modules/uploader/templates/uploaderAddTpl.html:22 -#: frontend/src/modules/uploader/templates/uploaderAddTpl.html:23 +#: frontend/src/modules/uploader/templates/uploaderAddTpl.html:20 +#: frontend/src/modules/uploader/templates/uploaderAddTpl.html:21 msgid "upl.btn.title" msgstr "Datei auswählen…" -#: frontend/src/modules/uploader/views/uploaderItemFooterVw.ts:30 +#: frontend/src/modules/uploader/views/uploaderItemFooterVw.ts:32 msgid "upl.del.btn" msgstr "Datei löschen" -#: frontend/src/modules/uploader/views/uploaderAddVw.ts:19 -#: frontend/src/modules/uploader/views/uploaderAddVw.ts:155 +#: frontend/src/modules/uploader/views/uploaderAddVw.ts:26 +#: frontend/src/modules/uploader/views/uploaderAddVw.ts:163 msgid "upl.failure" msgstr "Beim Hochladen ist ein Fehler aufgetreten." -#: frontend/src/modules/uploader/templates/uploadItemAudioTpl.html:4 -#: frontend/src/modules/uploader/templates/uploadItemImageTpl.html:4 -#: frontend/src/modules/uploader/templates/uploadItemVideoTpl.html:4 -#: frontend/src/modules/uploader/templates/uploadItemAudioTpl.html:5 -#: frontend/src/modules/uploader/templates/uploadItemImageTpl.html:5 -#: frontend/src/modules/uploader/templates/uploadItemVideoTpl.html:5 -msgid "upl.loading" -msgstr "Lade" - -#: frontend/src/modules/uploader/views/uploaderCollectionVw.ts:11 -#: frontend/src/modules/uploader/views/uploaderCollectionVw.ts:27 +#: frontend/src/modules/uploader/views/menu/uploaderMenuTitleVw.ts:9 +#: frontend/src/modules/uploader/views/menu/uploaderMenuTitleVw.ts:12 +msgid "upl.menu.search.t" +msgstr "Suche" + +#: frontend/src/modules/uploader/views/menu/uploaderMenuSortVw.ts:28 +#: frontend/src/modules/uploader/views/menu/uploaderMenuSortVw.ts:40 +msgid "upl.menu.sort.size" +msgstr "Größe" + +#: frontend/src/modules/uploader/views/menu/uploaderMenuSortVw.ts:28 +#: frontend/src/modules/uploader/views/menu/uploaderMenuSortVw.ts:39 +msgid "upl.menu.sort.time" +msgstr "Zeit" + +#: frontend/src/modules/uploader/views/menu/uploaderMenuTypeVw.ts:19 +msgid "upl.menu.type.all" +msgstr "Art: Alle" + +#: frontend/src/modules/uploader/views/menu/uploaderMenuTypeVw.ts:19 +#: frontend/src/modules/uploader/views/menu/uploaderMenuTypeVw.ts:39 +msgid "upl.mime.type.app" +msgstr "Anwendungsdatei" + +#: frontend/src/modules/uploader/views/menu/uploaderMenuTypeVw.ts:19 +#: frontend/src/modules/uploader/views/menu/uploaderMenuTypeVw.ts:43 +msgid "upl.mime.type.audio" +msgstr "Audio" + +#: frontend/src/modules/uploader/views/menu/uploaderMenuTypeVw.ts:19 +#: frontend/src/modules/uploader/views/menu/uploaderMenuTypeVw.ts:47 +msgid "upl.mime.type.image" +msgstr "Bild" + +#: frontend/src/modules/uploader/views/menu/uploaderMenuTypeVw.ts:19 +#: frontend/src/modules/uploader/views/menu/uploaderMenuTypeVw.ts:51 +msgid "upl.mime.type.text" +msgstr "Text" + +#: frontend/src/modules/uploader/views/menu/uploaderMenuTypeVw.ts:19 +#: frontend/src/modules/uploader/views/menu/uploaderMenuTypeVw.ts:55 +msgid "upl.mime.type.video" +msgstr "Video" + +#: frontend/src/modules/uploader/views/uploaderCollectionVw.ts:12 +#: frontend/src/modules/uploader/views/uploaderCollectionVw.ts:32 msgid "upl.ncy" -msgstr "Noch nichts hochgeladen." +msgstr "Keine Uploads gefunden." -#: frontend/src/modules/uploader/views/uploaderAdd/uploaderAddDragAreaVw.ts:42 -#: frontend/src/modules/uploader/views/uploaderAdd/uploaderAddDragAreaVw.ts:65 +#: frontend/src/modules/uploader/views/uploaderAdd/uploaderAddDragAreaVw.ts:40 +#: frontend/src/modules/uploader/views/uploaderAdd/uploaderAddDragAreaVw.ts:63 msgid "upl.new.title" msgstr "Datei hier hineinziehen" -#: frontend/src/modules/answering/editor/MenuButton/MenuButtonUploadView.ts:27 -#: frontend/src/modules/uploader/views/uploaderAdd/uploaderAddDragAreaVw.ts:39 -#: frontend/src/modules/answering/editor/MenuButton/MenuButtonUploadView.ts:72 +#: frontend/src/modules/answering/editor/MenuButton/MenuButtonUploadView.ts:25 +#: frontend/src/modules/uploader/views/uploaderAdd/uploaderAddDragAreaVw.ts:38 +#: frontend/src/modules/answering/editor/MenuButton/MenuButtonUploadView.ts:77 msgid "upl.title" msgstr "Hochladen" -#: frontend/src/modules/user/userVw.ts:25 +#: frontend/src/modules/user/userVw.ts:27 msgid "upl.title.pl" msgstr "Uploads" @@ -268,7 +303,7 @@ msgstr "Datei wurde nicht erkannt." msgid "upl.vald.e.fileExists" msgstr "Datei mit gleichen Namen wurde bereits hochgeladen." -#: src/Template/Users/view.ctp:323 +#: src/Template/Users/view.ctp:325 msgid "user.block.hours" msgstr "{hours} Stunden" diff --git a/frontend/src/locale/en.po b/frontend/src/locale/en.po index a89b896e2..7a0022bc1 100644 --- a/frontend/src/locale/en.po +++ b/frontend/src/locale/en.po @@ -52,24 +52,24 @@ msgid "answer.subject.t" msgstr "Subject" #: frontend/src/modules/answering/answering.ts:109 -#: frontend/src/modules/answering/answering.ts:304 +#: frontend/src/modules/answering/answering.ts:305 msgid "answer.submit.e.t" msgstr "Error: Posting Could Not Be Saved" #: frontend/src/modules/answering/answering.ts:109 -#: frontend/src/modules/answering/answering.ts:261 -#: frontend/src/modules/answering/answering.ts:303 +#: frontend/src/modules/answering/answering.ts:262 +#: frontend/src/modules/answering/answering.ts:304 msgid "api.generic.e.exp" msgstr "" "Couldn't reach the internet server. Check your connection and try again." #: frontend/src/modules/answering/answering.ts:109 -#: frontend/src/modules/answering/answering.ts:262 +#: frontend/src/modules/answering/answering.ts:263 msgid "api.generic.e.t" msgstr "Error: Couldn't Connect to Server" #: frontend/src/modules/bookmarks/views/bookmarkItemVw.ts:23 -#: frontend/src/modules/bookmarks/views/bookmarkItemVw.ts:88 +#: frontend/src/modules/bookmarks/views/bookmarkItemVw.ts:90 msgid "bkm.delete.failure" msgstr "Error: Bookmark could not be deleted." @@ -167,8 +167,8 @@ msgstr "Abort" msgid "posting.delete.title" msgstr "Delete Posting" -#: frontend/src/views/postingActionSolves.ts:22 -#: frontend/src/views/postingActionSolves.ts:33 +#: frontend/src/views/postingActionSolves.ts:23 +#: frontend/src/views/postingActionSolves.ts:34 msgid "posting.helpful" msgstr "Mark entry as helpful." @@ -207,55 +207,90 @@ msgstr "Size" msgid "upl.add.speed.t" msgstr "Speed" -#: frontend/src/modules/uploader/templates/uploaderAddTpl.html:12 -#: frontend/src/modules/uploader/templates/uploaderAddTpl.html:13 +#: frontend/src/modules/uploader/templates/uploaderAddTpl.html:10 +#: frontend/src/modules/uploader/templates/uploaderAddTpl.html:11 msgid "upl.btn.abort.title" msgstr "Abort upload" -#: frontend/src/modules/answering/editor/MenuButton/MenuButtonUploadView.ts:25 +#: frontend/src/modules/answering/editor/MenuButton/MenuButtonUploadView.ts:23 msgid "upl.btn.insert" msgstr "Insert" -#: frontend/src/modules/uploader/templates/uploaderAddTpl.html:22 -#: frontend/src/modules/uploader/templates/uploaderAddTpl.html:23 +#: frontend/src/modules/uploader/templates/uploaderAddTpl.html:20 +#: frontend/src/modules/uploader/templates/uploaderAddTpl.html:21 msgid "upl.btn.title" msgstr "Chose file…" -#: frontend/src/modules/uploader/views/uploaderItemFooterVw.ts:30 +#: frontend/src/modules/uploader/views/uploaderItemFooterVw.ts:32 msgid "upl.del.btn" msgstr "Delete file" -#: frontend/src/modules/uploader/views/uploaderAddVw.ts:19 -#: frontend/src/modules/uploader/views/uploaderAddVw.ts:155 +#: frontend/src/modules/uploader/views/uploaderAddVw.ts:26 +#: frontend/src/modules/uploader/views/uploaderAddVw.ts:163 msgid "upl.failure" msgstr "Error occurred on upload." -#: frontend/src/modules/uploader/templates/uploadItemAudioTpl.html:4 -#: frontend/src/modules/uploader/templates/uploadItemImageTpl.html:4 -#: frontend/src/modules/uploader/templates/uploadItemVideoTpl.html:4 -#: frontend/src/modules/uploader/templates/uploadItemAudioTpl.html:5 -#: frontend/src/modules/uploader/templates/uploadItemImageTpl.html:5 -#: frontend/src/modules/uploader/templates/uploadItemVideoTpl.html:5 -msgid "upl.loading" -msgstr "Loading" - -#: frontend/src/modules/uploader/views/uploaderCollectionVw.ts:11 -#: frontend/src/modules/uploader/views/uploaderCollectionVw.ts:27 +#: frontend/src/modules/uploader/views/menu/uploaderMenuTitleVw.ts:9 +#: frontend/src/modules/uploader/views/menu/uploaderMenuTitleVw.ts:12 +msgid "upl.menu.search.t" +msgstr "Search" + +#: frontend/src/modules/uploader/views/menu/uploaderMenuSortVw.ts:28 +#: frontend/src/modules/uploader/views/menu/uploaderMenuSortVw.ts:40 +msgid "upl.menu.sort.size" +msgstr "Size" + +#: frontend/src/modules/uploader/views/menu/uploaderMenuSortVw.ts:28 +#: frontend/src/modules/uploader/views/menu/uploaderMenuSortVw.ts:39 +msgid "upl.menu.sort.time" +msgstr "Time" + +#: frontend/src/modules/uploader/views/menu/uploaderMenuTypeVw.ts:19 +msgid "upl.menu.type.all" +msgstr "Type: All" + +#: frontend/src/modules/uploader/views/menu/uploaderMenuTypeVw.ts:19 +#: frontend/src/modules/uploader/views/menu/uploaderMenuTypeVw.ts:39 +msgid "upl.mime.type.app" +msgstr "Application file" + +#: frontend/src/modules/uploader/views/menu/uploaderMenuTypeVw.ts:19 +#: frontend/src/modules/uploader/views/menu/uploaderMenuTypeVw.ts:43 +msgid "upl.mime.type.audio" +msgstr "Audio" + +#: frontend/src/modules/uploader/views/menu/uploaderMenuTypeVw.ts:19 +#: frontend/src/modules/uploader/views/menu/uploaderMenuTypeVw.ts:47 +msgid "upl.mime.type.image" +msgstr "Image" + +#: frontend/src/modules/uploader/views/menu/uploaderMenuTypeVw.ts:19 +#: frontend/src/modules/uploader/views/menu/uploaderMenuTypeVw.ts:51 +msgid "upl.mime.type.text" +msgstr "Text" + +#: frontend/src/modules/uploader/views/menu/uploaderMenuTypeVw.ts:19 +#: frontend/src/modules/uploader/views/menu/uploaderMenuTypeVw.ts:55 +msgid "upl.mime.type.video" +msgstr "Video" + +#: frontend/src/modules/uploader/views/uploaderCollectionVw.ts:12 +#: frontend/src/modules/uploader/views/uploaderCollectionVw.ts:32 msgid "upl.ncy" -msgstr "No uploads yet." +msgstr "No uploads found." -#: frontend/src/modules/uploader/views/uploaderAdd/uploaderAddDragAreaVw.ts:42 -#: frontend/src/modules/uploader/views/uploaderAdd/uploaderAddDragAreaVw.ts:65 +#: frontend/src/modules/uploader/views/uploaderAdd/uploaderAddDragAreaVw.ts:40 +#: frontend/src/modules/uploader/views/uploaderAdd/uploaderAddDragAreaVw.ts:63 msgid "upl.new.title" msgstr "Drop File Here" -#: frontend/src/modules/answering/editor/MenuButton/MenuButtonUploadView.ts:27 -#: frontend/src/modules/uploader/views/uploaderAdd/uploaderAddDragAreaVw.ts:39 -#: frontend/src/modules/answering/editor/MenuButton/MenuButtonUploadView.ts:72 +#: frontend/src/modules/answering/editor/MenuButton/MenuButtonUploadView.ts:25 +#: frontend/src/modules/uploader/views/uploaderAdd/uploaderAddDragAreaVw.ts:38 +#: frontend/src/modules/answering/editor/MenuButton/MenuButtonUploadView.ts:77 msgid "upl.title" msgstr "Uploads" -#: frontend/src/modules/user/userVw.ts:25 +#: frontend/src/modules/user/userVw.ts:27 msgid "upl.title.pl" msgstr "Uploads" @@ -269,7 +304,7 @@ msgstr "Didn't find a file." msgid "upl.vald.e.fileExists" msgstr "File with same name already uploaded." -#: src/Template/Users/view.ctp:323 +#: src/Template/Users/view.ctp:325 msgid "user.block.hours" msgstr "{hours} hours" diff --git a/frontend/src/models/PostingMdl.ts b/frontend/src/models/PostingMdl.ts index 0a2494195..c29dff126 100644 --- a/frontend/src/models/PostingMdl.ts +++ b/frontend/src/models/PostingMdl.ts @@ -19,14 +19,20 @@ export default abstract class PostingModel extends JsonApiModel { _.defaults(defaults, { category_id: undefined, id: undefined, - pid: undefined, + pid: 0, + solves: 0, subject: '', - text: '', + text: undefined, }); super(defaults, options); } public isRoot(): boolean { - return !this.get('pid'); + const pid = this.get('pid'); + if (!_.isNumber(pid)) { + throw new Error('pid is not a number.'); + } + return pid === 0; } + } diff --git a/frontend/src/modules/answering/Draft.ts b/frontend/src/modules/answering/Draft.ts index cb70fe077..bc265e06f 100644 --- a/frontend/src/modules/answering/Draft.ts +++ b/frontend/src/modules/answering/Draft.ts @@ -169,13 +169,16 @@ export default class DraftView extends View { if (!this.enabled) { return; } - if (!this.model.get('id')) { - // Do only when creating a new draft, not on an existing one. + + /// Send empty subject and text only on existing draft to delete it. + const isNewDraft = !this.model.get('id'); + if (isNewDraft) { if (!this.model.get('subject') && !this.model.get('text')) { // Don't send empty data. return; } } + this.model.save(null, { success: (model, response, options) => { this.showSaved(); }, }); diff --git a/frontend/src/modules/answering/editor/MenuButton/MenuButtonUploadView.ts b/frontend/src/modules/answering/editor/MenuButton/MenuButtonUploadView.ts index 560c7702b..e18106339 100644 --- a/frontend/src/modules/answering/editor/MenuButton/MenuButtonUploadView.ts +++ b/frontend/src/modules/answering/editor/MenuButton/MenuButtonUploadView.ts @@ -1,11 +1,18 @@ +/** + * Saito - The Threaded Web Forum + * + * @copyright Copyright (c) the Saito Project Developers + * @link https://github.com/Schlaefer/Saito + * @license http://opensource.org/licenses/MIT + */ + import { Model } from 'backbone'; import { View } from 'backbone.marionette'; -import { Channel } from 'backbone.radio'; import BbcodeTag from 'lib/saito/Editor/Bbcode/BbcodeTag'; import App from 'models/app'; import ModalDialog from 'modules/modalDialog/modalDialog'; import UploaderVw from 'modules/uploader/uploader'; -import * as _ from 'underscore'; +import { defaults, template } from 'underscore'; import { AbstractMenuButtonView } from './AbstractMenuButtonView'; /** @@ -18,10 +25,9 @@ class InsertVw extends View { * @param options marionette init */ public constructor(options: object = {}) { - _.defaults(options, { - className: 'imageUploader-action', + options = defaults(options, { events: { 'click @ui.button': 'onButtonClick' }, - template: _.template(` + template: template(` `), @@ -67,9 +73,20 @@ class MenuButtonUploadView extends AbstractMenuButtonView { () => { return new InsertVw({ channel: this.channel }); }); - const uploadsView = new UploaderVw(); + const uploadsView = new UploaderVw({ + permission: { + 'saito.plugin.uploader.add': true, + 'saito.plugin.uploader.delete': true, + 'saito.plugin.uploader.view': true, + }, + userId: App.currentUser.get('id'), + }); - ModalDialog.show(uploadsView, { title: $.i18n.__('upl.title'), width: 'max' }); + ModalDialog.show(uploadsView, { + title: $.i18n.__('upl.title'), + trailing: true, + width: 'max', + }); } } diff --git a/frontend/src/modules/answering/views/SubjectInputVw.ts b/frontend/src/modules/answering/views/SubjectInputVw.ts index 80587ab2a..0456e4a6e 100644 --- a/frontend/src/modules/answering/views/SubjectInputVw.ts +++ b/frontend/src/modules/answering/views/SubjectInputVw.ts @@ -184,9 +184,8 @@ export default class SubjectInputView extends View { private setProgress(cssClass: ProgressBarState) { const $progress = this.getUI('progressBar'); Object.keys(ProgressBarState).forEach((key) => { - // @td bogus - const k = key as unknown as number; - $progress.removeClass(ProgressBarState[k]); + const state = ProgressBarState[key as keyof typeof ProgressBarState]; + $progress.removeClass(state); }); $progress.addClass(cssClass); } diff --git a/frontend/src/modules/bookmarks/views/bookmarkItemVw.ts b/frontend/src/modules/bookmarks/views/bookmarkItemVw.ts index cdb2f3dc1..c1823383f 100644 --- a/frontend/src/modules/bookmarks/views/bookmarkItemVw.ts +++ b/frontend/src/modules/bookmarks/views/bookmarkItemVw.ts @@ -78,19 +78,22 @@ export default class extends Mn.View { protected handleDelete() { this._deactivateInteractions(); - this.$el.hide('slide', null, 500); - this.model.destroy({ - error: () => { - this._activateInteractions(); - this.$el.show('slide', null, 500); - const notification = { - code: 1527277946, - message: $.i18n.__('bkm.delete.failure'), - type: 'error', - }; - App.eventBus.trigger('notification', notification); - }, - wait: true, + this.$el.hide('slide', null, 500, () => { + // Wait until the animation finished, so it isn't interrupted by the + // Ma-colleciton redraw on model removal. + this.model.destroy({ + error: () => { + this._activateInteractions(); + this.$el.show('slide', null, 500); + const notification = { + code: 1527277946, + message: $.i18n.__('bkm.delete.failure'), + type: 'error', + }; + App.eventBus.trigger('notification', notification); + }, + wait: true, + }); }); } diff --git a/frontend/src/modules/modalDialog/modalDialog.ts b/frontend/src/modules/modalDialog/modalDialog.ts index fe5a0351d..c970a9b93 100644 --- a/frontend/src/modules/modalDialog/modalDialog.ts +++ b/frontend/src/modules/modalDialog/modalDialog.ts @@ -1,16 +1,36 @@ +/** + * Saito - The Threaded Web Forum + * + * @copyright Copyright (c) the Saito Project Developers + * @link https://github.com/Schlaefer/Saito + * @license http://opensource.org/licenses/MIT + */ + import { Model } from 'backbone'; -import { View } from 'backbone.marionette'; +import { View, ViewOptions } from 'backbone.marionette'; import App from 'models/app'; import Tpl from 'modules/modalDialog/templates/modalDialog.html'; -import _ from 'underscore'; +import { defaults, delay } from 'underscore'; + +interface IModalDialogOptions { + /** + * Insert content after modal dialog is fully shown + */ + trailing: boolean; + title: string; + width: string; +} class ModalDialogView extends View { - // el: '#saito-modal-dialog', + /** + * View which will be rendered as main content into the modal dialog + */ + protected contentView: View|undefined; - private defaults: object; + private defaults: Partial; public constructor(options: any = {}) { - _.defaults(options, { + options = defaults(options, { regions: { content: '#saito-modal-dialog-content', }, @@ -18,8 +38,10 @@ class ModalDialogView extends View { }); super(options); this.defaults = { + trailing: false, width: 'normal', }; + this.contentView = undefined; } public initialize() { @@ -32,15 +54,20 @@ class ModalDialogView extends View { * @param {Marionette.View} content * @param {Object} */ - public show(content: View, options: any) { - options = _.defaults(options, this.defaults); + public show(content: View, options: Partial = {}) { + const showOptions = defaults(options, this.defaults) as IModalDialogOptions; this.model.set('title', options.title || ''); this.render(); - // puts content into dialog - this.showChildView('content', content); + this.setWidth(showOptions.width); - this.setWidth(options.width); + if (showOptions.trailing) { + // Insert content after showing the modal + this.contentView = content; + } else { + // Insert content before showing the modal + this.showContent(content); + } // shows BS dialog this.$el.parent().on('shown.bs.modal', () => { @@ -63,11 +90,29 @@ class ModalDialogView extends View { public invalidInput() { this.$el.addClass('animation shake'); - _.delay(() => { + delay(() => { this.$el.removeClass('animation shake', 1000); }); } + /** + * Called after the modal dialog is fully shown + */ + protected onShown() { + // Show trailing + if (this.contentView !== undefined) { + this.showContent(this.contentView); + this.contentView = undefined; + } + } + + /** + * Shows content + */ + protected showContent(contentView: View) { + this.showChildView('content', contentView); + } + private setWidth(width: string) { switch (width) { case 'max': diff --git a/frontend/src/modules/posting/Geshi.ts b/frontend/src/modules/posting/Geshi.ts index 1ac21a4d6..768c66b7e 100644 --- a/frontend/src/modules/posting/Geshi.ts +++ b/frontend/src/modules/posting/Geshi.ts @@ -68,7 +68,7 @@ class GeshiView extends View { private renderText() { if (this.model.get('isPlaintext') && this.plainText) { - this.block.text(this.plainText).wrapInner('
');
+            this.block.text(this.plainText).wrapInner('
');
         } else if (this.htmlText) {
             this.block.html(this.htmlText);
         }
diff --git a/frontend/src/modules/posting/models/PostingModel.ts b/frontend/src/modules/posting/models/PostingModel.ts
index 6638173ae..eaf038d08 100644
--- a/frontend/src/modules/posting/models/PostingModel.ts
+++ b/frontend/src/modules/posting/models/PostingModel.ts
@@ -1,25 +1,26 @@
 import { Model } from 'backbone';
 import * as $ from 'jquery';
 import App from 'models/app';
+import PostingMdl from 'models/PostingMdl';
 import _ from 'underscore';
 
-class PostingModel extends Model {
-    public defaults() {
-        const posting = {
-            text: null,
-        };
-        const meta = {
+class PostingModel extends PostingMdl {
+    public saitoUrl: string;
+
+    public constructor(defaults: any = {}, options: any = {}) {
+        _.defaults(defaults, {
             html: '',
             isAnsweringFormShown: false,
             isBookmarked: false,
-            isSolves: false,
-        };
+        });
+        super(defaults, options);
 
-        return _.extend(posting, meta);
+        // This model is currently not used for sending
+        this.saitoUrl = 'foo';
     }
 
     public initialize() {
-        this.listenTo(this, 'change:isSolves', this.syncSolved);
+        this.listenTo(this, 'change:solves', this.onChangeSolves);
     }
 
     public fetchHtml(options: any) {
@@ -34,15 +35,7 @@ class PostingModel extends Model {
         });
     }
 
-    public isRoot(): boolean {
-        const pid = this.get('pid');
-        if (!_.isNumber(pid)) {
-            throw new Error('pid is not a number.');
-        }
-        return pid === 0;
-    }
-
-    private syncSolved() {
+    private onChangeSolves() {
         $.ajax({
             dataType: 'json',
             type: 'POST',
diff --git a/frontend/src/modules/uploader/collections/leftToRenderCl.ts b/frontend/src/modules/uploader/collections/leftToRenderCl.ts
new file mode 100644
index 000000000..d728dadef
--- /dev/null
+++ b/frontend/src/modules/uploader/collections/leftToRenderCl.ts
@@ -0,0 +1,25 @@
+/**
+ * Saito - The Threaded Web Forum
+ *
+ * @copyright Copyright (c) the Saito Project Developers
+ * @link https://github.com/Schlaefer/Saito
+ * @license http://opensource.org/licenses/MIT
+ */
+
+import { Collection, Model } from 'backbone';
+
+class LeftToRenderCl extends Collection {
+    public constructor() {
+        super();
+        this.setComparator('time');
+    }
+
+    public setComparator(after: string = 'time') {
+        after = (after === 'time') ? 'id' : after;
+        this.comparator = (model: Model) => {
+            return -1 * model.get(after);
+        };
+    }
+}
+
+export default LeftToRenderCl;
diff --git a/frontend/src/modules/uploader/collections/uploads.ts b/frontend/src/modules/uploader/collections/uploads.ts
index 534d4def4..ab362b04d 100644
--- a/frontend/src/modules/uploader/collections/uploads.ts
+++ b/frontend/src/modules/uploader/collections/uploads.ts
@@ -1,4 +1,13 @@
+/**
+ * Saito - The Threaded Web Forum
+ *
+ * @copyright Copyright (c) the Saito Project Developers
+ * @link https://github.com/Schlaefer/Saito
+ * @license http://opensource.org/licenses/MIT
+ */
+
 import { JsonApiCollection, JsonApiModel } from 'lib/backbone/jsonApi';
+import UploadFilter from '../lib/uploadFilter';
 
 class UploadsModel extends JsonApiModel {
     protected saitoUrl = 'uploads/';
@@ -8,11 +17,17 @@ export default class extends JsonApiCollection {
     /** Bb collection model */
     public model = UploadsModel;
 
+    public uploadFilter!: UploadFilter;
+
     protected saitoUrl = 'uploads/';
 
-    /** Bb comparator */
-    public comparator = (model: UploadsModel) => {
-        // sort by latest first (negate ID for DESC)
-        return -1 * model.get('id');
+    public initialize() {
+        this.uploadFilter = new UploadFilter();
+    }
+
+    public getFiltered() {
+        return this.filter((model) => {
+            return this.uploadFilter.filter(model);
+        });
     }
 }
diff --git a/frontend/src/modules/uploader/lib/uploadFilter.ts b/frontend/src/modules/uploader/lib/uploadFilter.ts
new file mode 100644
index 000000000..cbe268658
--- /dev/null
+++ b/frontend/src/modules/uploader/lib/uploadFilter.ts
@@ -0,0 +1,82 @@
+/**
+ * Saito - The Threaded Web Forum
+ *
+ * @copyright Copyright (c) the Saito Project Developers
+ * @link https://github.com/Schlaefer/Saito
+ * @license http://opensource.org/licenses/MIT
+ */
+
+import { Model } from 'backbone';
+import { isEmpty } from 'underscore';
+
+/**
+ * Implements filtering of upload models
+ */
+class UploadFilter {
+    /**
+     * Search for upload file title/name
+     */
+    protected title: string|undefined;
+
+    /**
+     * Search string for upload type
+     */
+    protected mime: string|undefined;
+
+    /**
+     * Mime-type setter
+     * @param type Set mime subtype to check against
+     */
+    public setMime(type: string): void {
+        this.mime = isEmpty(type) ? undefined : type;
+    }
+
+    /**
+     * Title search setter
+     * @param title Title search string
+     */
+    public setTitle(title: string): void {
+        this.title = isEmpty(title) ? undefined : title;
+    }
+
+    /**
+     * Reset filter (unfiltered)
+     */
+    public reset(): void {
+        this.mime = undefined;
+        this.title = undefined;
+    }
+
+    /**
+     * Filter callback to check if a model should be shown
+     * @param model Model to apply the filter to
+     * @returns True if model should be shown, false otherwise.
+     */
+    public filter(model: Model): boolean {
+        /// Allow other cards (i.e. add new upload) without filtering
+        const isCardOfUploadedItem: boolean = (model.get('mime') !== undefined);
+        if (!isCardOfUploadedItem) {
+            return true;
+        }
+
+        /// Check for mime type
+        if (this.mime !== undefined) {
+            if (model.get('mime').indexOf(this.mime) !== 0) {
+                return false;
+            }
+        }
+
+        /// Check for title
+        if (this.title !== undefined) {
+            const title = model.get('title') + ' ' + model.get('name');
+            if (title.toLowerCase().indexOf(this.title.toLowerCase()) === -1) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+}
+
+export default UploadFilter;
diff --git a/frontend/src/modules/uploader/templates/uploadItemAudioTpl.html b/frontend/src/modules/uploader/templates/uploadItemAudioTpl.html
index c5e576e3a..3634a627d 100644
--- a/frontend/src/modules/uploader/templates/uploadItemAudioTpl.html
+++ b/frontend/src/modules/uploader/templates/uploadItemAudioTpl.html
@@ -1,12 +1,7 @@
 
     
-
- - <%- $.i18n.__('upl.loading') %> - -
-
- -
+ +
diff --git a/frontend/src/modules/uploader/templates/uploadItemGenericTpl.html b/frontend/src/modules/uploader/templates/uploadItemGenericTpl.html index 82eca1a25..df5f28193 100644 --- a/frontend/src/modules/uploader/templates/uploadItemGenericTpl.html +++ b/frontend/src/modules/uploader/templates/uploadItemGenericTpl.html @@ -5,5 +5,5 @@ - -
+ +
diff --git a/frontend/src/modules/uploader/templates/uploadItemImageTpl.html b/frontend/src/modules/uploader/templates/uploadItemImageTpl.html index 3749fb515..6437b7c9f 100644 --- a/frontend/src/modules/uploader/templates/uploadItemImageTpl.html +++ b/frontend/src/modules/uploader/templates/uploadItemImageTpl.html @@ -1,18 +1,13 @@
-
- - <%- $.i18n.__('upl.loading') %> - -
- - data-src="<%= thumbnail_url %>" + src="<%= thumbnail_url %>" <% } else { %> - data-src="<%= url %>" + src="<%= url %>" <% } %> >
- -
+ +
diff --git a/frontend/src/modules/uploader/templates/uploadItemVideoTpl.html b/frontend/src/modules/uploader/templates/uploadItemVideoTpl.html index d800a6e94..bd4ce73f6 100644 --- a/frontend/src/modules/uploader/templates/uploadItemVideoTpl.html +++ b/frontend/src/modules/uploader/templates/uploadItemVideoTpl.html @@ -1,12 +1,7 @@
-
- - <%- $.i18n.__('upl.loading') %> - -
-
- -
+ +
diff --git a/frontend/src/modules/uploader/templates/uploaderAddTpl.html b/frontend/src/modules/uploader/templates/uploaderAddTpl.html index 9c8c16edb..c6eb4f83c 100644 --- a/frontend/src/modules/uploader/templates/uploaderAddTpl.html +++ b/frontend/src/modules/uploader/templates/uploaderAddTpl.html @@ -7,27 +7,24 @@