mirror of
https://github.com/flarum/core.git
synced 2025-08-13 11:54:32 +02:00
Compare commits
31 Commits
dw/drop-bo
...
as/v1.2.1-
Author | SHA1 | Date | |
---|---|---|---|
|
dd5c516156 | ||
|
085c44ec63 | ||
|
60600f4d2b | ||
|
7a22527b72 | ||
|
bd4d53323c | ||
|
ad69cf84fe | ||
|
aa77df46ee | ||
|
19e48617f0 | ||
|
d8b83cc372 | ||
|
a04b420295 | ||
|
5f4b5c0841 | ||
|
beae75dab3 | ||
|
e304cf7cb5 | ||
|
9f87674626 | ||
|
54329d0827 | ||
|
a7aad46068 | ||
|
7551a14ae5 | ||
|
f4c29db182 | ||
|
a291134da1 | ||
|
c702f5e228 | ||
|
749e7e34f7 | ||
|
67821d95bd | ||
|
aa44677df3 | ||
|
3978efa533 | ||
|
687e1e2789 | ||
|
7cec4d1f42 | ||
|
fbe1a48bec | ||
|
17a8d2c9d8 | ||
|
85ee80659d | ||
|
af77214967 | ||
|
7c3b51fec0 |
15
.github/workflows/backend.yml
vendored
Normal file
15
.github/workflows/backend.yml
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
name: Core PHP
|
||||
|
||||
on: [workflow_dispatch, push, pull_request]
|
||||
|
||||
# The reusable workflow definitions will be moved to the `flarum/framework` repo soon.
|
||||
# This will break your current script.
|
||||
# When this happens, run `flarum-cli audit infra --fix` to update your infrastructure.
|
||||
|
||||
jobs:
|
||||
run:
|
||||
uses: flarum/.github/.github/workflows/REUSABLE_backend.yml@main
|
||||
with:
|
||||
enable_backend_testing: true
|
||||
|
||||
backend_directory: .
|
21
.github/workflows/frontend.yml
vendored
Normal file
21
.github/workflows/frontend.yml
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
name: Core JS
|
||||
|
||||
on: [workflow_dispatch, push, pull_request]
|
||||
|
||||
# The reusable workflow definitions will be moved to the `flarum/framework` repo soon.
|
||||
# This will break your current script.
|
||||
# When this happens, run `flarum-cli audit infra --fix` to update your infrastructure.
|
||||
|
||||
jobs:
|
||||
run:
|
||||
uses: flarum/.github/.github/workflows/REUSABLE_frontend.yml@main
|
||||
with:
|
||||
enable_bundlewatch: true
|
||||
enable_prettier: true
|
||||
enable_typescript: true
|
||||
|
||||
frontend_directory: ./js
|
||||
main_git_branch: master
|
||||
|
||||
secrets:
|
||||
bundlewatch_github_token: ${{ secrets.BUNDLEWATCH_GITHUB_TOKEN }}
|
137
.github/workflows/js.yml
vendored
137
.github/workflows/js.yml
vendored
@@ -1,137 +0,0 @@
|
||||
name: JS
|
||||
|
||||
on: [workflow_dispatch, push, pull_request]
|
||||
|
||||
env:
|
||||
NODE_VERSION: 16
|
||||
|
||||
jobs:
|
||||
prettier:
|
||||
name: Prettier
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
cache: "yarn"
|
||||
cache-dependency-path: js/yarn.lock
|
||||
|
||||
- name: Install JS dependencies
|
||||
run: yarn install --immutable
|
||||
working-directory: ./js
|
||||
|
||||
- name: Check JS formatting
|
||||
run: yarn run format-check
|
||||
working-directory: ./js
|
||||
|
||||
typecheck:
|
||||
name: Typecheck
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
cache: "yarn"
|
||||
cache-dependency-path: js/yarn.lock
|
||||
|
||||
- name: Install JS dependencies
|
||||
run: yarn --frozen-lockfile
|
||||
working-directory: ./js
|
||||
|
||||
- name: Typecheck
|
||||
run: yarn run check-typings
|
||||
working-directory: ./js
|
||||
|
||||
type-coverage:
|
||||
name: Type Coverage
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
cache: "yarn"
|
||||
cache-dependency-path: js/yarn.lock
|
||||
|
||||
- name: Install JS dependencies
|
||||
run: yarn --frozen-lockfile
|
||||
working-directory: ./js
|
||||
|
||||
- name: Check type coverage
|
||||
run: yarn run check-typings-coverage
|
||||
working-directory: ./js
|
||||
|
||||
build-prod:
|
||||
name: Build and commit
|
||||
runs-on: ubuntu-latest
|
||||
needs: [prettier, typecheck, type-coverage]
|
||||
|
||||
# Only commit JS on push to master branch
|
||||
# Remember to change in `build-test` job too
|
||||
if: github.ref == 'refs/heads/master' && github.event_name == 'push'
|
||||
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
cache: "yarn"
|
||||
cache-dependency-path: js/yarn.lock
|
||||
|
||||
# Our action will install npm, cd into `./js`, run `npm run build` and
|
||||
# `npm run build-typings`, then commit and upload any changes
|
||||
- name: Build production JS
|
||||
uses: flarum/action-build@2
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
build_script: build
|
||||
package_manager: yarn
|
||||
typings_script: build-typings
|
||||
|
||||
build-test:
|
||||
name: Test build
|
||||
runs-on: ubuntu-latest
|
||||
needs: [prettier, typecheck, type-coverage]
|
||||
|
||||
# Inverse check of `build-prod`
|
||||
# Remember to change in `build-prod` job too
|
||||
if: github.ref != 'refs/heads/master' || github.event_name != 'push'
|
||||
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
cache: "yarn"
|
||||
cache-dependency-path: js/yarn.lock
|
||||
|
||||
# Our action will install npm, cd into `./js`, run `npm run build` and
|
||||
# `npm run build-typings`, then commit and upload any changes
|
||||
- name: Build production JS
|
||||
uses: flarum/action-build@2
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
build_script: build
|
||||
package_manager: yarn
|
||||
typings_script: build-typings
|
||||
do_not_commit: true
|
45
.github/workflows/pr_size_change.yml
vendored
45
.github/workflows/pr_size_change.yml
vendored
@@ -1,45 +0,0 @@
|
||||
name: Bundle size checker
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
push:
|
||||
paths:
|
||||
- "js/**"
|
||||
pull_request:
|
||||
paths:
|
||||
- "js/**"
|
||||
|
||||
jobs:
|
||||
bundlewatch:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
name: Bundlewatch
|
||||
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: "14"
|
||||
|
||||
- name: Use npm v7
|
||||
run: sudo npm install -g npm@7.x.x
|
||||
|
||||
- name: Install JS dependencies
|
||||
# We need to use `npm install` here. If we don't, the workflow will fail.
|
||||
run: npm install
|
||||
working-directory: ./js
|
||||
|
||||
- name: Build production assets
|
||||
run: npm run build
|
||||
working-directory: ./js
|
||||
|
||||
- name: Check bundle size change
|
||||
run: node_modules/.bin/bundlewatch --config .bundlewatch.config.json
|
||||
working-directory: ./js
|
||||
env:
|
||||
BUNDLEWATCH_GITHUB_TOKEN: ${{ secrets.BUNDLEWATCH_GITHUB_TOKEN }}
|
||||
CI_COMMIT_SHA: ${{ github.event.pull_request.head.sha }}
|
79
.github/workflows/test.yml
vendored
79
.github/workflows/test.yml
vendored
@@ -1,79 +0,0 @@
|
||||
name: Tests
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
php: [7.3, 7.4, '8.0', '8.1']
|
||||
service: ['mysql:5.7', mariadb]
|
||||
prefix: ['', flarum_]
|
||||
|
||||
include:
|
||||
- service: 'mysql:5.7'
|
||||
db: MySQL
|
||||
- service: mariadb
|
||||
db: MariaDB
|
||||
- prefix: flarum_
|
||||
prefixStr: (prefix)
|
||||
|
||||
exclude:
|
||||
- php: 7.3
|
||||
service: 'mysql:5.7'
|
||||
prefix: flarum_
|
||||
- php: 7.3
|
||||
service: mariadb
|
||||
prefix: flarum_
|
||||
- php: 8.0
|
||||
service: 'mysql:5.7'
|
||||
prefix: flarum_
|
||||
- php: 8.0
|
||||
service: mariadb
|
||||
prefix: flarum_
|
||||
|
||||
services:
|
||||
mysql:
|
||||
image: ${{ matrix.service }}
|
||||
ports:
|
||||
- 13306:3306
|
||||
|
||||
name: 'PHP ${{ matrix.php }} / ${{ matrix.db }} ${{ matrix.prefixStr }}'
|
||||
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@0b9d33cd0782337377999751fc10ea079fdd7104 # pin@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php }}
|
||||
coverage: xdebug
|
||||
extensions: curl, dom, gd, json, mbstring, openssl, pdo_mysql, tokenizer, zip
|
||||
tools: phpunit, composer:v2
|
||||
|
||||
# The authentication alter is necessary because newer mysql versions use the `caching_sha2_password` driver,
|
||||
# which isn't supported prior to PHP7.4
|
||||
# When we drop support for PHP7.3, we should remove this from the setup.
|
||||
- name: Create MySQL Database
|
||||
run: |
|
||||
sudo systemctl start mysql
|
||||
mysql -uroot -proot -e 'CREATE DATABASE flarum_test;' --port 13306
|
||||
mysql -uroot -proot -e "ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'root';" --port 13306
|
||||
|
||||
- name: Install Composer dependencies
|
||||
run: composer install
|
||||
|
||||
- name: Setup Composer tests
|
||||
run: composer test:setup
|
||||
env:
|
||||
DB_PORT: 13306
|
||||
DB_PASSWORD: root
|
||||
DB_PREFIX: ${{ matrix.prefix }}
|
||||
|
||||
- name: Run Composer tests
|
||||
run: composer test
|
||||
env:
|
||||
COMPOSER_PROCESS_TIMEOUT: 600
|
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,6 +1,7 @@
|
||||
/vendor
|
||||
composer.lock
|
||||
composer.phar
|
||||
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
tests/.phpunit.result.cache
|
||||
|
115
CHANGELOG.md
115
CHANGELOG.md
@@ -1,5 +1,120 @@
|
||||
# Changelog
|
||||
|
||||
## [1.2.1](https://github.com/flarum/core/compare/v1.2.0...v1.2.1)
|
||||
|
||||
### Fixed
|
||||
- Don't escape single quotes in discussion title meta tags (60600f4d2b8f0c5dac94c329041427a0a08fad42)
|
||||
|
||||
## [1.2.0](https://github.com/flarum/core/compare/v1.1.1...v1.2.0)
|
||||
|
||||
### Added
|
||||
- View `README` documentation in extension pages (https://github.com/flarum/core/pull/3094).
|
||||
- Declare & Use CSS Custom Properties (https://github.com/flarum/core/pull/3146).
|
||||
- Lazy draw dropdowns to improve performance (https://github.com/flarum/core/pull/2925).
|
||||
- Default Settings Extender (https://github.com/flarum/core/pull/3127).
|
||||
- Add `textarea` setting type to admin pages (https://github.com/flarum/core/pull/3141).
|
||||
- Allow registering settings as `Less` config vars through Settings Extender (https://github.com/flarum/core/pull/3011).
|
||||
- Allow replacing of blade template namespaces via extender (https://github.com/flarum/core/pull/3167).
|
||||
- Update to Webpack 5 (https://github.com/flarum/core/pull/3135).
|
||||
- Introduce `Less` custom function extender with a `is-extension-enabled` function (https://github.com/flarum/core/pull/3190).
|
||||
- Support for `few` in ICU Message syntax (https://github.com/flarum/core/pull/3122).
|
||||
- ES6 local support for number formatting (https://github.com/flarum/core/pull/3099).
|
||||
- Added dedicated endpoint for retrieving single groups (https://github.com/flarum/core/pull/3084).
|
||||
- Callback `loadWhere` relation eager loading extender (https://github.com/flarum/core/pull/3116).
|
||||
- Extensible document title driver implementation (https://github.com/flarum/core/pull/3109).
|
||||
- Type checks, typescript coverage GH action (https://github.com/flarum/core/pull/3136).
|
||||
- Add color indicator in appearance admin page instead of validating colors (https://github.com/flarum/core/pull/3140).
|
||||
- Add typing files for our translator libraries (https://github.com/flarum/core/pull/3175).
|
||||
- `StatusWidget` tools extensibility (https://github.com/flarum/core/pull/3189).
|
||||
- Allow switching the `ImageManager` driver (https://github.com/flarum/core/pull/3195).
|
||||
- Events for notification read/all read actions (https://github.com/flarum/core/pull/3203).
|
||||
|
||||
### Changed
|
||||
- Testing with php8.1 (https://github.com/flarum/core/pull/3102).
|
||||
- Migrate fully to Yarn (https://github.com/flarum/core/pull/3155).
|
||||
- Handle post rendering errors to avoid crashes (https://github.com/flarum/core/pull/3061).
|
||||
- Added basic filtering, sorting, and pagination to groups endpoint (https://github.com/flarum/core/pull/3084).
|
||||
- Pass IP address to API Client pipeline (https://github.com/flarum/core/pull/3124).
|
||||
- Rename Extension Page "Uninstall" to "Purge" (https://github.com/flarum/core/pull/3123).
|
||||
- [A11Y] Improve accessibility for discussion reply count on post stream (https://github.com/flarum/core/pull/3090).
|
||||
- Improved post loading support (https://github.com/flarum/core/pull/3100).
|
||||
- Rewrite SubtreeRetainer into Typescript (https://github.com/flarum/core/pull/3137).
|
||||
- Rewrite ModalManager and state to Typescript (https://github.com/flarum/core/pull/3007).
|
||||
- Rewrite frontend application files to Typescript (https://github.com/flarum/core/pull/3006).
|
||||
- Allow extensions to modify the minimum search length in the Search component (https://github.com/flarum/core/pull/3130).
|
||||
- Allow use of any tag in `listItems` helper (https://github.com/flarum/core/pull/3147).
|
||||
- Replace `for ... in` with `Array.reduce` (https://github.com/flarum/core/pull/3149).
|
||||
- Page title format is now implemented through translations (https://github.com/flarum/core/pull/3077, https://github.com/flarum/core/pull/3228)
|
||||
- Add `aria-label` attribute to the navigation drawer button (https://github.com/flarum/core/pull/3157).
|
||||
- Convert extend util to TypeScript (https://github.com/flarum/core/pull/2928).
|
||||
- Better typings for DiscussionListState (https://github.com/flarum/core/pull/3132).
|
||||
- Rewrite ItemList, update `ItemList` typings (https://github.com/flarum/core/pull/3005).
|
||||
- Add priority order to discussion page controls (https://github.com/flarum/core/pull/3165).
|
||||
- Use `@php` in Blade templates (https://github.com/flarum/core/pull/3172).
|
||||
- Convert some common classes/utils to TS (https://github.com/flarum/core/pull/2929).
|
||||
- Convert routes to Typescript (https://github.com/flarum/core/pull/3177).
|
||||
- Move admin `colorItems` to an `ItemList` (https://github.com/flarum/core/pull/3186).
|
||||
- Centralize pagination/canonical meta URL generation in Document (https://github.com/flarum/core/pull/3077).
|
||||
- Use revision versioner to allow custom asset versioning (https://github.com/flarum/core/pull/3183).
|
||||
- Split up application error handling (https://github.com/flarum/core/pull/3184).
|
||||
- Make SlugManager available to blade template (https://github.com/flarum/core/pull/3194).
|
||||
- Convert models to TS (https://github.com/flarum/core/pull/3174).
|
||||
- Allow loading relations in other discussion endpoints (https://github.com/flarum/core/pull/3191).
|
||||
- Improve selected text stylization (https://github.com/flarum/core/pull/2961).
|
||||
- Extract notification `primaryControl` items to an ItemList (https://github.com/flarum/core/pull/3204).
|
||||
- Frontend code housekeeping (#3214, #3213).
|
||||
- Only retain scroll position if coming from discussion (https://github.com/flarum/core/pull/3229).
|
||||
- Use `aria-live` regions to focus screenreader attention on alerts as they appear (https://github.com/flarum/core/pull/3237).
|
||||
- Prevent unwarranted `a11y` warnings on custom Button subclasses (https://github.com/flarum/core/pull/3238).
|
||||
|
||||
### Fixed
|
||||
- Missing locale text in the user editing modal (https://github.com/flarum/core/pull/3093).
|
||||
- Dashes in table prefix prevent installation (https://github.com/flarum/core/pull/3089).
|
||||
- Missing autocomplete attributes to input fields (https://github.com/flarum/core/pull/3088).
|
||||
- Missing route parameters throwing an error (https://github.com/flarum/core/pull/3118).
|
||||
- Mail settings select component never used (https://github.com/flarum/core/pull/3120).
|
||||
- White avatar image throws javascript errors on the profile page (https://github.com/flarum/core/pull/3119).
|
||||
- Unformatted avatar upload validation errors (https://github.com/flarum/core/pull/2946).
|
||||
- Webkit input clear button shows up with the custom one (https://github.com/flarum/core/pull/3128).
|
||||
- Media query breakpoints conflict with Windows display scaling (https://github.com/flarum/core/pull/3139).
|
||||
- `typeof this` not recognized by some IDEs (https://github.com/flarum/core/pull/3142).
|
||||
- `Model.save()` cannot save `null` `hasOne` relationship (https://github.com/flarum/core/pull/3131).
|
||||
- Edit post `until reply` policy broken on PHP 8 (https://github.com/flarum/core/pull/3145).
|
||||
- Inaccurate `Component.component` argument typings (https://github.com/flarum/core/pull/3148).
|
||||
- Scrolling notification list infinitely repeats (https://github.com/flarum/core/pull/3159).
|
||||
- Argument for INFO constant was assigned to `maxfiles` argument incorrectly (bfd81a83cfd0fa8125395a147ff0c9ce622f38e3).
|
||||
- `Activated` event is sent every time an email is confirmed instead of just once (https://github.com/flarum/core/pull/3163).
|
||||
- [A11Y] Modal close button missing accessible label (https://github.com/flarum/core/pull/3161).
|
||||
- [A11Y] Auth modal inputs missing accessible labels (https://github.com/flarum/core/pull/3207).
|
||||
- [A11Y] Triggering click on drawer button can cause layered backdrops (https://github.com/flarum/core/pull/3018).
|
||||
- [A11Y] Focus can leave open nav drawer on mobile (https://github.com/flarum/core/pull/3018).
|
||||
- [A11Y] Post action items not showing when focus is within the post (https://github.com/flarum/core/pull/3173).
|
||||
- [A11Y] Missing accessible label for alert dismiss button (https://github.com/flarum/core/pull/3237).
|
||||
- Error accessing the forum after saving a setting with more than 65k characters (https://github.com/flarum/core/pull/3162).
|
||||
- Cannot restart queue from within (https://github.com/flarum/core/pull/3166).
|
||||
- `Post--by-actor` not showing when comparing user instances (https://github.com/flarum/core/pull/3170).
|
||||
- Incorrect typings for Modal `hide()` method (https://github.com/flarum/core/pull/3180).
|
||||
- Avatar Upload throws errors with correct mimetype and incorrect extension (https://github.com/flarum/core/pull/3181).
|
||||
- Clicking the dropdown button on a post opens all dropdowns in `Post-actions` (https://github.com/flarum/core/pull/3185).
|
||||
- `getPlainContent()` causes external content to be fetched (https://github.com/flarum/core/pull/3193).
|
||||
- `listItems` not accepting all `Mithril.Children` (https://github.com/flarum/core/pull/3176).
|
||||
- Notifications mark as read option updates all notifications including the read ones (https://github.com/flarum/core/pull/3202).
|
||||
- Post meta permalink not properly generated (https://github.com/flarum/core/pull/3216).
|
||||
- Broken contribution link in README (https://github.com/flarum/core/pull/3211).
|
||||
- `WelcomeHero` is displayed when content is empty (https://github.com/flarum/core/pull/3219).
|
||||
- `last_activity_at, last_seen_at` updated on all API requests (https://github.com/flarum/core/pull/3231).
|
||||
- `RememberMe` access token updated twice in API requests (https://github.com/flarum/core/pull/3233).
|
||||
- Error in `funding` item in `composer.json` bricks the frontend (https://github.com/flarum/core/pull/3239).
|
||||
- Escaped quotes in window title (https://github.com/flarum/core/pull/3264)
|
||||
- `schedule:list` command fails due to missing timezone configuration.
|
||||
|
||||
### Deprecated
|
||||
- Unused `evented` utility (https://github.com/flarum/core/pull/3125).
|
||||
|
||||
## [1.1.1](https://github.com/flarum/core/compare/v1.1.0...v1.1.1)
|
||||
|
||||
### Fixed
|
||||
- Performance issue with very large communities.
|
||||
|
||||
## [1.1.0](https://github.com/flarum/core/compare/v1.0.4...v1.1.0)
|
||||
|
||||
|
@@ -86,7 +86,7 @@
|
||||
"wikimedia/less.php": "^3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"flarum/testing": "1.0@dev"
|
||||
"flarum/testing": "^1.0.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
@@ -107,6 +107,28 @@
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.x-dev"
|
||||
},
|
||||
"flarum-cli": {
|
||||
"excludeScaffolding": [
|
||||
"LICENSE.md",
|
||||
"js/tsconfig.json",
|
||||
"js/webpack.config.js"
|
||||
],
|
||||
"modules": {
|
||||
"backendTesting": true,
|
||||
"js": true,
|
||||
"gitConf": true,
|
||||
"githubActions": true,
|
||||
"prettier": true,
|
||||
"typescript": true,
|
||||
"bundlewatch": true,
|
||||
"editorConfig": true,
|
||||
"styleci": true,
|
||||
"admin": true,
|
||||
"forum": true,
|
||||
"jsCommon": true,
|
||||
"css": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
|
@@ -1,2 +1,2 @@
|
||||
export * from './src/common';
|
||||
export * from './src/forum';
|
||||
export * from './src/admin';
|
14
js/dist-typings/common/index.d.ts
vendored
14
js/dist-typings/common/index.d.ts
vendored
@@ -1,3 +1,13 @@
|
||||
import * as Extend from "./extend/index";
|
||||
import app from "./app";
|
||||
import 'expose-loader?exposes=$,jQuery!jquery';
|
||||
import 'expose-loader?exposes=m!mithril';
|
||||
import 'expose-loader?exposes=dayjs!dayjs';
|
||||
import 'bootstrap/js/affix';
|
||||
import 'bootstrap/js/dropdown';
|
||||
import 'bootstrap/js/modal';
|
||||
import 'bootstrap/js/tooltip';
|
||||
import 'bootstrap/js/transition';
|
||||
import 'jquery.hotkeys/jquery.hotkeys';
|
||||
import * as Extend from './extend/index';
|
||||
import app from './app';
|
||||
export { Extend, app };
|
||||
import './utils/arrayFlatPolyfill';
|
||||
|
2
js/dist-typings/forum/routes.d.ts
vendored
2
js/dist-typings/forum/routes.d.ts
vendored
@@ -10,7 +10,7 @@ export declare function makeRouteHelpers(app: ForumApplication): {
|
||||
/**
|
||||
* Generate a URL to a discussion.
|
||||
*/
|
||||
discussion: (discussion: Discussion, near: number) => string;
|
||||
discussion: (discussion: Discussion, near?: number | undefined) => string;
|
||||
/**
|
||||
* Generate a URL to a post.
|
||||
*/
|
||||
|
2
js/dist/admin.js
generated
vendored
2
js/dist/admin.js
generated
vendored
File diff suppressed because one or more lines are too long
2
js/dist/admin.js.map
generated
vendored
2
js/dist/admin.js.map
generated
vendored
File diff suppressed because one or more lines are too long
2
js/dist/forum.js
generated
vendored
2
js/dist/forum.js
generated
vendored
File diff suppressed because one or more lines are too long
2
js/dist/forum.js.map
generated
vendored
2
js/dist/forum.js.map
generated
vendored
File diff suppressed because one or more lines are too long
@@ -1,2 +1,2 @@
|
||||
export * from './src/common';
|
||||
export * from './src/admin';
|
||||
export * from './src/forum';
|
@@ -1,52 +1,51 @@
|
||||
{
|
||||
"private": true,
|
||||
"name": "@flarum/core",
|
||||
"prettier": "@flarum/prettier-config",
|
||||
"dependencies": {
|
||||
"@askvortsov/rich-icu-message-formatter": "^0.2.1",
|
||||
"@ultraq/icu-message-formatter": "^0.12.0",
|
||||
"bootstrap": "^3.4.1",
|
||||
"clsx": "^1.1.1",
|
||||
"color-thief-browser": "^2.0.2",
|
||||
"dayjs": "^1.10.7",
|
||||
"dialog-polyfill": "^0.5.6",
|
||||
"focus-trap": "^6.7.1",
|
||||
"jquery": "^3.6.0",
|
||||
"jquery.hotkeys": "^0.1.0",
|
||||
"mithril": "^2.0.4",
|
||||
"nanoid": "^3.1.30",
|
||||
"punycode": "^2.1.1",
|
||||
"textarea-caret": "^3.1.0",
|
||||
"throttle-debounce": "^3.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@flarum/prettier-config": "^1.0.0",
|
||||
"@types/jquery": "^3.5.10",
|
||||
"@types/mithril": "^2.0.8",
|
||||
"@types/punycode": "^2.1.0",
|
||||
"@types/textarea-caret": "^3.0.1",
|
||||
"bundlewatch": "^0.3.2",
|
||||
"cross-env": "^7.0.3",
|
||||
"expose-loader": "^3.1.0",
|
||||
"flarum-tsconfig": "^1.0.2",
|
||||
"flarum-webpack-config": "^2.0.0",
|
||||
"prettier": "^2.5.1",
|
||||
"typescript": "^4.5.4",
|
||||
"typescript-coverage-report": "^0.6.1",
|
||||
"webpack": "^5.65.0",
|
||||
"webpack-cli": "^4.9.1",
|
||||
"webpack-merge": "^5.8.0"
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "webpack --mode development --watch",
|
||||
"build": "webpack --mode production",
|
||||
"analyze": "cross-env ANALYZER=true npm run build",
|
||||
"format": "prettier --write src",
|
||||
"format-check": "prettier --check src",
|
||||
"clean-typings": "npx rimraf dist-typings && mkdir dist-typings",
|
||||
"build-typings": "npm run clean-typings && cp -r src/@types dist-typings/@types && tsc",
|
||||
"check-typings": "tsc --noEmit --emitDeclarationOnly false",
|
||||
"check-typings-coverage": "typescript-coverage-report"
|
||||
},
|
||||
"packageManager": "yarn@3.1.1"
|
||||
"private": true,
|
||||
"name": "@flarum/core",
|
||||
"prettier": "@flarum/prettier-config",
|
||||
"dependencies": {
|
||||
"@askvortsov/rich-icu-message-formatter": "^0.2.4",
|
||||
"@ultraq/icu-message-formatter": "^0.12.0",
|
||||
"bootstrap": "^3.4.1",
|
||||
"clsx": "^1.1.1",
|
||||
"color-thief-browser": "^2.0.2",
|
||||
"dayjs": "^1.10.7",
|
||||
"focus-trap": "^6.7.1",
|
||||
"jquery": "^3.6.0",
|
||||
"jquery.hotkeys": "^0.1.0",
|
||||
"mithril": "^2.0.4",
|
||||
"nanoid": "^3.1.30",
|
||||
"punycode": "^2.1.1",
|
||||
"textarea-caret": "^3.1.0",
|
||||
"throttle-debounce": "^3.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@flarum/prettier-config": "^1.0.0",
|
||||
"@types/jquery": "^3.5.10",
|
||||
"@types/mithril": "^2.0.8",
|
||||
"@types/punycode": "^2.1.0",
|
||||
"@types/textarea-caret": "^3.0.1",
|
||||
"bundlewatch": "^0.3.2",
|
||||
"cross-env": "^7.0.3",
|
||||
"expose-loader": "^3.1.0",
|
||||
"flarum-tsconfig": "^1.0.2",
|
||||
"flarum-webpack-config": "^2.0.0",
|
||||
"prettier": "^2.5.1",
|
||||
"typescript": "^4.5.4",
|
||||
"typescript-coverage-report": "^0.6.1",
|
||||
"webpack": "^5.65.0",
|
||||
"webpack-cli": "^4.9.1",
|
||||
"webpack-merge": "^5.8.0"
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "webpack --mode development --watch",
|
||||
"build": "webpack --mode production",
|
||||
"analyze": "cross-env ANALYZER=true yarn build",
|
||||
"format": "prettier --write src",
|
||||
"format-check": "prettier --check src",
|
||||
"clean-typings": "npx rimraf dist-typings && mkdir dist-typings",
|
||||
"build-typings": "npm run clean-typings && tsc && [ -e src/@types ] && cp -r src/@types dist-typings/@types",
|
||||
"check-typings": "tsc --noEmit --emitDeclarationOnly false",
|
||||
"check-typings-coverage": "typescript-coverage-report"
|
||||
},
|
||||
"packageManager": "yarn@3.1.1"
|
||||
}
|
||||
|
46
js/src/@types/modals/index.d.ts
vendored
46
js/src/@types/modals/index.d.ts
vendored
@@ -1,46 +0,0 @@
|
||||
/**
|
||||
* Only supported natively in Chrome. In testing in Safari Technology Preview.
|
||||
*
|
||||
* Please register modals with the dialog polyfill before use:
|
||||
*
|
||||
* ```js
|
||||
* dialogPolyfill.registerDialog(dialogElementReference);
|
||||
* ```
|
||||
*
|
||||
* ### Events
|
||||
*
|
||||
* Two events are fired by dialogs:
|
||||
* - `cancel` - Fired when the user instructs the browser that they wish to dismiss the current open dialog.
|
||||
* - `close` - Fired when the dialog is closed.
|
||||
*
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLDialogElement
|
||||
*/
|
||||
interface HTMLDialogElement {
|
||||
/**
|
||||
* Shows the `<dialog>` element as a top-layered element in the document.
|
||||
*/
|
||||
show(): void;
|
||||
/**
|
||||
* Displays the dialog as a modal, over the top of any other dialogs that
|
||||
* might be present. Interaction outside the dialog is blocked.
|
||||
*/
|
||||
showModal(): void;
|
||||
/**
|
||||
* If the `<dialog>` element is currently being shown, dismiss it.
|
||||
*
|
||||
* @param returnValue An optional return value for the dialog to hold. *This is currently unused by Flarum.*
|
||||
*/
|
||||
close(returnValue?: string): void;
|
||||
|
||||
/**
|
||||
* A return value for the dialog to hold.
|
||||
*
|
||||
* *This is currently unused by Flarum.*
|
||||
*/
|
||||
returnValue: string;
|
||||
|
||||
/**
|
||||
* Whether the dialog is currently open.
|
||||
*/
|
||||
open: boolean;
|
||||
}
|
@@ -18,7 +18,7 @@ export default class EditCustomCssModal extends SettingsModal {
|
||||
})}
|
||||
</p>,
|
||||
<div className="Form-group">
|
||||
<textarea className="FormControl" rows="30" bidi={this.setting('custom_less')} />
|
||||
<textarea className="FormControl" rows="30" bidi={this.setting('custom_less')} spellcheck={false} />
|
||||
</div>,
|
||||
];
|
||||
}
|
||||
|
@@ -547,7 +547,11 @@ export default class Application {
|
||||
|
||||
console.group(`${method} ${url} ${status}`);
|
||||
|
||||
console.error(...(formattedErrors || [e]));
|
||||
if (formattedErrors.length) {
|
||||
console.error(...formattedErrors);
|
||||
} else {
|
||||
console.error(e);
|
||||
}
|
||||
|
||||
console.groupEnd();
|
||||
}
|
||||
|
@@ -1,5 +1,6 @@
|
||||
import app from '../common/app';
|
||||
import { FlarumRequestOptions } from './Application';
|
||||
import { fireDeprecationWarning } from './helpers/fireDebugWarning';
|
||||
import Store, { ApiPayloadSingle, ApiResponseSingle, MetaInformation } from './Store';
|
||||
|
||||
export interface ModelIdentifier {
|
||||
@@ -111,6 +112,19 @@ export default abstract class Model {
|
||||
|
||||
if ('attributes' in data) {
|
||||
this.data.attributes ||= {};
|
||||
|
||||
// @deprecated
|
||||
// Filter out relationships that got in by accident.
|
||||
for (const key in data.attributes) {
|
||||
const val = data.attributes[key];
|
||||
if (val && val instanceof Model) {
|
||||
fireDeprecationWarning('Providing models as attributes to `Model.pushData()` or `Model.pushAttributes()` is deprecated.', '3249');
|
||||
delete data.attributes[key];
|
||||
data.relationships ||= {};
|
||||
data.relationships[key] = { data: Model.getIdentifier(val) };
|
||||
}
|
||||
}
|
||||
|
||||
Object.assign(this.data.attributes, data.attributes);
|
||||
}
|
||||
|
||||
|
@@ -8,7 +8,6 @@ import type ModalManagerState from '../states/ModalManagerState';
|
||||
import type RequestError from '../utils/RequestError';
|
||||
import type ModalManager from './ModalManager';
|
||||
import fireDebugWarning from '../helpers/fireDebugWarning';
|
||||
import classList from '../utils/classList';
|
||||
|
||||
export interface IInternalModalAttrs {
|
||||
state: ModalManagerState;
|
||||
@@ -16,63 +15,16 @@ export interface IInternalModalAttrs {
|
||||
animateHide: ModalManager['animateHide'];
|
||||
}
|
||||
|
||||
export interface IDismissibleOptions {
|
||||
/**
|
||||
* @deprecated Check specific individual attributes instead. Will be removed in Flarum 2.0.
|
||||
*/
|
||||
isDismissible: boolean;
|
||||
viaCloseButton: boolean;
|
||||
viaEscKey: boolean;
|
||||
viaBackdropClick: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* The `Modal` component displays a modal dialog, wrapped in a form. Subclasses
|
||||
* should implement the `className`, `title`, and `content` methods.
|
||||
*/
|
||||
export default abstract class Modal<ModalAttrs extends IInternalModalAttrs = IInternalModalAttrs> extends Component<ModalAttrs> {
|
||||
// TODO: [Flarum 2.0] remove `isDismissible` static attribute
|
||||
/**
|
||||
* Determine whether or not the modal should be dismissible via an 'x' button.
|
||||
*
|
||||
* @deprecated Use the individual `isDismissibleVia...` attributes instead and remove references to this.
|
||||
*/
|
||||
static readonly isDismissible: boolean = true;
|
||||
|
||||
/**
|
||||
* Can the model be dismissed with a close button (X)?
|
||||
*
|
||||
* If `false`, no close button is shown.
|
||||
*/
|
||||
protected static readonly isDismissibleViaCloseButton: boolean = true;
|
||||
/**
|
||||
* Can the modal be dismissed by pressing the Esc key on a keyboard?
|
||||
*/
|
||||
protected static readonly isDismissibleViaEscKey: boolean = true;
|
||||
/**
|
||||
* Can the modal be dismissed via a click on the backdrop.
|
||||
*/
|
||||
protected static readonly isDismissibleViaBackdropClick: boolean = true;
|
||||
|
||||
static get dismissibleOptions(): IDismissibleOptions {
|
||||
// If someone sets this to `false`, provide the same behaviour as previous versions of Flarum.
|
||||
if (!this.isDismissible) {
|
||||
return {
|
||||
isDismissible: false,
|
||||
viaCloseButton: false,
|
||||
viaEscKey: false,
|
||||
viaBackdropClick: false,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
isDismissible: true,
|
||||
viaCloseButton: this.isDismissibleViaCloseButton,
|
||||
viaEscKey: this.isDismissibleViaEscKey,
|
||||
viaBackdropClick: this.isDismissibleViaBackdropClick,
|
||||
};
|
||||
}
|
||||
|
||||
protected loading: boolean = false;
|
||||
|
||||
/**
|
||||
@@ -135,16 +87,16 @@ export default abstract class Modal<ModalAttrs extends IInternalModalAttrs = IIn
|
||||
}
|
||||
|
||||
return (
|
||||
<dialog className={classList('Modal modal-dialog fade', this.className())}>
|
||||
<div className={'Modal modal-dialog ' + this.className()}>
|
||||
<div className="Modal-content">
|
||||
{this.dismissibleOptions.viaCloseButton && (
|
||||
{(this.constructor as typeof Modal).isDismissible && (
|
||||
<div className="Modal-close App-backControl">
|
||||
<Button
|
||||
icon="fas fa-times"
|
||||
onclick={() => this.hide()}
|
||||
className="Button Button--icon Button--link"
|
||||
aria-label={app.translator.trans('core.lib.modal.close')}
|
||||
/>
|
||||
{Button.component({
|
||||
icon: 'fas fa-times',
|
||||
onclick: () => this.hide(),
|
||||
className: 'Button Button--icon Button--link',
|
||||
'aria-label': app.translator.trans('core.lib.modal.close'),
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -158,7 +110,7 @@ export default abstract class Modal<ModalAttrs extends IInternalModalAttrs = IIn
|
||||
{this.content()}
|
||||
</form>
|
||||
</div>
|
||||
</dialog>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -223,8 +175,4 @@ export default abstract class Modal<ModalAttrs extends IInternalModalAttrs = IIn
|
||||
this.onready();
|
||||
}
|
||||
}
|
||||
|
||||
private get dismissibleOptions(): IDismissibleOptions {
|
||||
return (this.constructor as typeof Modal).dismissibleOptions;
|
||||
}
|
||||
}
|
||||
|
@@ -22,16 +22,12 @@ export default class ModalManager extends Component<IModalManagerAttrs> {
|
||||
*/
|
||||
protected modalShown: boolean = false;
|
||||
|
||||
protected modalClosing: boolean = false;
|
||||
|
||||
protected clickStartedOnBackdrop: boolean = false;
|
||||
|
||||
view(vnode: Mithril.VnodeDOM<IModalManagerAttrs, this>): Mithril.Children {
|
||||
const modal = this.attrs.state.modal;
|
||||
const Tag = modal?.componentClass;
|
||||
|
||||
return (
|
||||
<div className="ModalManager modal">
|
||||
<div className="ModalManager modal fade">
|
||||
{!!Tag && (
|
||||
<Tag
|
||||
key={modal?.key}
|
||||
@@ -48,7 +44,12 @@ export default class ModalManager extends Component<IModalManagerAttrs> {
|
||||
oncreate(vnode: Mithril.VnodeDOM<IModalManagerAttrs, this>): void {
|
||||
super.oncreate(vnode);
|
||||
|
||||
this.focusTrap = createFocusTrap(this.element as HTMLElement);
|
||||
// Ensure the modal state is notified about a closed modal, even when the
|
||||
// DOM-based Bootstrap JavaScript code triggered the closing of the modal,
|
||||
// e.g. via ESC key or a click on the modal backdrop.
|
||||
this.$().on('hidden.bs.modal', this.attrs.state.close.bind(this.attrs.state));
|
||||
|
||||
this.focusTrap = createFocusTrap(this.element as HTMLElement, { allowOutsideClick: true });
|
||||
}
|
||||
|
||||
onupdate(vnode: Mithril.VnodeDOM<IModalManagerAttrs, this>): void {
|
||||
@@ -64,93 +65,35 @@ export default class ModalManager extends Component<IModalManagerAttrs> {
|
||||
});
|
||||
}
|
||||
|
||||
private get dialogElement(): HTMLDialogElement {
|
||||
return this.element.querySelector('dialog') as HTMLDialogElement;
|
||||
}
|
||||
|
||||
animateShow(readyCallback: () => void): void {
|
||||
if (!this.attrs.state.modal) return;
|
||||
|
||||
const dismissibleState = this.attrs.state.modal.componentClass.dismissibleOptions;
|
||||
const dismissible = !!this.attrs.state.modal.componentClass.isDismissible;
|
||||
|
||||
this.modalShown = true;
|
||||
|
||||
// Register with polyfill
|
||||
dialogPolyfill.registerDialog(this.dialogElement);
|
||||
|
||||
if (!dismissibleState.viaEscKey) this.dialogElement.addEventListener('cancel', this.preventEscPressHandler);
|
||||
if (dismissibleState.viaBackdropClick) {
|
||||
this.dialogElement.addEventListener('mousedown', (e) => this.handleBackdropMouseDown.call(this, e));
|
||||
this.dialogElement.addEventListener('click', (e) => this.handleBackdropClick.call(this, e));
|
||||
// If we are opening this modal while another modal is already open,
|
||||
// the shown event will not run, because the modal is already open.
|
||||
// So, we need to manually trigger the readyCallback.
|
||||
if (this.$().hasClass('in')) {
|
||||
readyCallback();
|
||||
return;
|
||||
}
|
||||
|
||||
this.dialogElement.addEventListener('transitionend', () => readyCallback(), { once: true });
|
||||
// Ensure the modal state is ALWAYS notified about a closed modal
|
||||
this.dialogElement.addEventListener('close', this.attrs.state.close.bind(this.attrs.state));
|
||||
|
||||
// Use close animation instead
|
||||
this.dialogElement.addEventListener('cancel', this.animateCloseHandler.bind(this));
|
||||
|
||||
this.dialogElement.showModal();
|
||||
|
||||
// Fade in
|
||||
requestAnimationFrame(() => {
|
||||
this.dialogElement.classList.add('in');
|
||||
});
|
||||
this.$()
|
||||
.one('shown.bs.modal', readyCallback)
|
||||
// @ts-expect-error: No typings available for Bootstrap modals.
|
||||
.modal({
|
||||
backdrop: dismissible || 'static',
|
||||
keyboard: dismissible,
|
||||
})
|
||||
.modal('show');
|
||||
}
|
||||
|
||||
animateHide(): void {
|
||||
if (this.modalClosing || !this.modalShown) return;
|
||||
this.modalClosing = true;
|
||||
// @ts-expect-error: No typings available for Bootstrap modals.
|
||||
this.$().modal('hide');
|
||||
|
||||
this.dialogElement.addEventListener(
|
||||
'transitionend',
|
||||
() => {
|
||||
this.dialogElement.close();
|
||||
this.dialogElement.removeEventListener('cancel', this.preventEscPressHandler);
|
||||
|
||||
this.modalShown = false;
|
||||
this.modalClosing = false;
|
||||
m.redraw();
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
|
||||
this.dialogElement.classList.remove('in');
|
||||
this.dialogElement.classList.add('out');
|
||||
}
|
||||
|
||||
protected animateCloseHandler(this: this, e: Event) {
|
||||
e.preventDefault();
|
||||
|
||||
this.animateHide();
|
||||
}
|
||||
|
||||
protected preventEscPressHandler(this: this, e: Event) {
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
protected handleBackdropMouseDown(this: this, e: MouseEvent) {
|
||||
// If it's a mousedown on the dialog element, the backdrop has been clicked.
|
||||
// If it was a mousedown in the modal, the element would be `div.Modal-content` or some other element.
|
||||
if (e.target !== this.dialogElement) return;
|
||||
|
||||
this.clickStartedOnBackdrop = true;
|
||||
window.addEventListener(
|
||||
'mouseup',
|
||||
() => {
|
||||
if (e.target !== this.dialogElement) this.clickStartedOnBackdrop = false;
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
}
|
||||
|
||||
protected handleBackdropClick(this: this, e: MouseEvent) {
|
||||
// If it's a click on the dialog element, the backdrop has been clicked.
|
||||
// If it was a click in the modal, the element would be `div.Modal-content` or some other element.
|
||||
if (e.target !== this.dialogElement || !this.clickStartedOnBackdrop) return;
|
||||
|
||||
this.clickStartedOnBackdrop = false;
|
||||
this.animateHide();
|
||||
this.modalShown = false;
|
||||
}
|
||||
}
|
||||
|
@@ -22,7 +22,7 @@ export default class RequestErrorModal<CustomAttrs extends IRequestErrorModalAtt
|
||||
|
||||
// If the error is already formatted, just add line endings;
|
||||
// else try to parse it as JSON and stringify it with indentation
|
||||
if (formattedError) {
|
||||
if (formattedError.length) {
|
||||
responseText = formattedError.join('\n\n');
|
||||
} else if (error.response) {
|
||||
responseText = JSON.stringify(error.response, null, 2);
|
||||
|
@@ -3,12 +3,9 @@ import 'expose-loader?exposes=$,jQuery!jquery';
|
||||
import 'expose-loader?exposes=m!mithril';
|
||||
import 'expose-loader?exposes=dayjs!dayjs';
|
||||
|
||||
// HTML dialog element polyfill from the Chrome Dev team: https://github.com/GoogleChrome/dialog-polyfill
|
||||
import dialogPolyfill from 'dialog-polyfill';
|
||||
window.dialogPolyfill = dialogPolyfill;
|
||||
|
||||
import 'bootstrap/js/affix';
|
||||
import 'bootstrap/js/dropdown';
|
||||
import 'bootstrap/js/modal';
|
||||
import 'bootstrap/js/tooltip';
|
||||
import 'bootstrap/js/transition';
|
||||
import 'jquery.hotkeys/jquery.hotkeys';
|
||||
@@ -33,6 +30,7 @@ import './utils/arrayFlatPolyfill';
|
||||
const tooltipGen = $.fn.tooltip;
|
||||
|
||||
// Remove in a future version of Flarum.
|
||||
// @ts-ignore
|
||||
$.fn.tooltip = function (options, caller) {
|
||||
// Show a warning when `$.tooltip` is used outside of the Tooltip component.
|
||||
// This functionality is deprecated and should not be used.
|
@@ -1,5 +1,5 @@
|
||||
import type Component from '../Component';
|
||||
import Modal, { IDismissibleOptions } from '../components/Modal';
|
||||
import Modal from '../components/Modal';
|
||||
|
||||
/**
|
||||
* Ideally, `show` would take a higher-kinded generic, ala:
|
||||
@@ -8,7 +8,7 @@ import Modal, { IDismissibleOptions } from '../components/Modal';
|
||||
* https://github.com/Microsoft/TypeScript/issues/1213
|
||||
* Therefore, we have to use this ugly, messy workaround.
|
||||
*/
|
||||
type UnsafeModalClass = ComponentClass<any, Modal> & { get dismissibleOptions(): IDismissibleOptions; component: typeof Component.component };
|
||||
type UnsafeModalClass = ComponentClass<any, Modal> & { isDismissible: boolean; component: typeof Component.component };
|
||||
|
||||
/**
|
||||
* Class used to manage modal state.
|
||||
|
@@ -138,7 +138,7 @@ export default class Post extends Component {
|
||||
classes.push('Post--by-actor');
|
||||
}
|
||||
|
||||
if (user?.id() === discussion.attribute('startUserId')) {
|
||||
if (user && user?.id() === discussion.attribute('startUserId')) {
|
||||
classes.push('Post--by-start-user');
|
||||
}
|
||||
|
||||
|
@@ -34,7 +34,7 @@ export function makeRouteHelpers(app: ForumApplication) {
|
||||
/**
|
||||
* Generate a URL to a discussion.
|
||||
*/
|
||||
discussion: (discussion: Discussion, near: number) => {
|
||||
discussion: (discussion: Discussion, near?: number) => {
|
||||
return app.route(near && near !== 1 ? 'discussion.near' : 'discussion', {
|
||||
id: discussion.slug(),
|
||||
near: near && near !== 1 ? near : undefined,
|
||||
|
@@ -213,7 +213,7 @@ export default {
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
hideAction() {
|
||||
this.pushAttributes({ hiddenAt: new Date(), hiddenUser: app.session.user });
|
||||
this.pushData({ attributes: { hiddenAt: new Date() }, relationships: { hiddenUser: app.session.user } });
|
||||
|
||||
return this.save({ isHidden: true });
|
||||
},
|
||||
@@ -224,7 +224,7 @@ export default {
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
restoreAction() {
|
||||
this.pushAttributes({ hiddenAt: null, hiddenUser: null });
|
||||
this.pushData({ attributes: { hiddenAt: null }, relationships: { hiddenUser: null } });
|
||||
|
||||
return this.save({ isHidden: false });
|
||||
},
|
||||
|
@@ -151,7 +151,7 @@ export default {
|
||||
*/
|
||||
hideAction() {
|
||||
if (!confirm(extractText(app.translator.trans('core.forum.post_controls.hide_confirmation')))) return;
|
||||
this.pushAttributes({ hiddenAt: new Date(), hiddenUser: app.session.user });
|
||||
this.pushData({ attributes: { hiddenAt: new Date() }, relationships: { hiddenUser: app.session.user } });
|
||||
|
||||
return this.save({ isHidden: true }).then(() => m.redraw());
|
||||
},
|
||||
@@ -162,7 +162,7 @@ export default {
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
restoreAction() {
|
||||
this.pushAttributes({ hiddenAt: null, hiddenUser: null });
|
||||
this.pushData({ attributes: { hiddenAt: null }, relationships: { hiddenUser: null } });
|
||||
|
||||
return this.save({ isHidden: false }).then(() => m.redraw());
|
||||
},
|
||||
|
18
js/yarn.lock
18
js/yarn.lock
@@ -5,14 +5,14 @@ __metadata:
|
||||
version: 5
|
||||
cacheKey: 8
|
||||
|
||||
"@askvortsov/rich-icu-message-formatter@npm:^0.2.1":
|
||||
version: 0.2.1
|
||||
resolution: "@askvortsov/rich-icu-message-formatter@npm:0.2.1"
|
||||
"@askvortsov/rich-icu-message-formatter@npm:^0.2.4":
|
||||
version: 0.2.4
|
||||
resolution: "@askvortsov/rich-icu-message-formatter@npm:0.2.4"
|
||||
dependencies:
|
||||
"@babel/runtime": ^7.11.2
|
||||
"@ultraq/array-utils": ^2.1.0
|
||||
"@ultraq/icu-message-formatter": ^0.12.0
|
||||
checksum: 8c6417cfa12d51cd03e361d9dfb5503db546d073634d4bed3439ddce8f739a89175f2e9898ac87ba8d8cadf96cc1887eb9f0d53bf3787fa5a507709b1b9e705b
|
||||
checksum: dc6ebec438f27d70564c6082506c7df7c31ff558948e58911370a23413fa7ea352e8c8931a100d920bb6696b5dde3e7723e7341e0dffdfba6c1105bdb4d170a5
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -1388,7 +1388,7 @@ __metadata:
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@flarum/core@workspace:."
|
||||
dependencies:
|
||||
"@askvortsov/rich-icu-message-formatter": ^0.2.1
|
||||
"@askvortsov/rich-icu-message-formatter": ^0.2.4
|
||||
"@flarum/prettier-config": ^1.0.0
|
||||
"@types/jquery": ^3.5.10
|
||||
"@types/mithril": ^2.0.8
|
||||
@@ -1401,7 +1401,6 @@ __metadata:
|
||||
color-thief-browser: ^2.0.2
|
||||
cross-env: ^7.0.3
|
||||
dayjs: ^1.10.7
|
||||
dialog-polyfill: ^0.5.6
|
||||
expose-loader: ^3.1.0
|
||||
flarum-tsconfig: ^1.0.2
|
||||
flarum-webpack-config: ^2.0.0
|
||||
@@ -2311,13 +2310,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"dialog-polyfill@npm:^0.5.6":
|
||||
version: 0.5.6
|
||||
resolution: "dialog-polyfill@npm:0.5.6"
|
||||
checksum: dde8d4b6a62b63b710e0d0d70b615d92ff08f3cb2b521e1f99b17e8220d9d55d0fdf9fc17fbe77b0ff1be817094e14b60c4c4bacd5456fba427ede48d2d90230
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"duplexer@npm:^0.1.1, duplexer@npm:^0.1.2":
|
||||
version: 0.1.2
|
||||
resolution: "duplexer@npm:0.1.2"
|
||||
|
@@ -6,44 +6,55 @@
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.Modal {
|
||||
border-width: 0;
|
||||
padding: 0;
|
||||
overflow: visible;
|
||||
border-radius: @border-radius;
|
||||
|
||||
transform: scale(0.9);
|
||||
transition: transform 0.2s ease-out, opacity 0.2s ease-out;
|
||||
|
||||
// only in polyfilled browsers
|
||||
&[role] {
|
||||
top: 0 !important;
|
||||
}
|
||||
// Modal background
|
||||
.modal-backdrop {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: var(--zindex-modal-background);
|
||||
background-color: var(--overlay-bg);
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s;
|
||||
|
||||
&.in {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Container that the modal scrolls within
|
||||
.ModalManager {
|
||||
display: none;
|
||||
overflow: hidden;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: var(--zindex-modal);
|
||||
-webkit-overflow-scrolling: touch;
|
||||
|
||||
// When fading in the modal, animate it to slide down
|
||||
.Modal {
|
||||
transform: scale(0.9);
|
||||
transition: transform 0.2s ease-out;
|
||||
}
|
||||
&.in .Modal {
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
.modal-open .ModalManager {
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
//! These MUST be defined separately
|
||||
//
|
||||
// When browsers do not understand a pseudoselector, the entire block is ignored,
|
||||
// meaning no backdrop would be visible at all.
|
||||
&::backdrop {
|
||||
// `::backdrop` does not inherit anything from parents, so we need to declare this here.
|
||||
// See: https://stackoverflow.com/a/63322762/11091039
|
||||
|
||||
--overlay-bg: @overlay-bg;
|
||||
background: var(--overlay-bg);
|
||||
}
|
||||
|
||||
+ .backdrop {
|
||||
background: var(--overlay-bg);
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
// Shell div to position the modal with bottom padding
|
||||
.Modal {
|
||||
position: relative;
|
||||
width: auto;
|
||||
margin: 10px;
|
||||
max-width: 600px;
|
||||
}
|
||||
|
||||
// Actual modal
|
||||
@@ -128,7 +139,13 @@
|
||||
bottom: 0;
|
||||
top: 0;
|
||||
overflow: auto;
|
||||
transition: transform 0.2s ease-out;
|
||||
transform: translate(0, 100vh);
|
||||
|
||||
&.in {
|
||||
-webkit-transform: none !important;
|
||||
transform: none !important;
|
||||
}
|
||||
&:before {
|
||||
content: " ";
|
||||
.header-background();
|
||||
@@ -157,10 +174,6 @@
|
||||
|
||||
@media @tablet-up {
|
||||
.Modal {
|
||||
border-radius: var(--border-radius);
|
||||
box-shadow: 0 7px 15px var(--shadow-color);
|
||||
width: 100%;
|
||||
max-width: 600px;
|
||||
margin: 120px auto;
|
||||
}
|
||||
.Modal-close {
|
||||
@@ -170,7 +183,10 @@
|
||||
z-index: 1;
|
||||
}
|
||||
.Modal-content {
|
||||
|
||||
border: 0;
|
||||
border-radius: var(--border-radius);
|
||||
box-shadow: 0 7px 15px var(--shadow-color);
|
||||
}
|
||||
.Modal--small {
|
||||
max-width: 375px;
|
||||
|
@@ -21,7 +21,7 @@ class Application
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const VERSION = '1.2.0-dev';
|
||||
const VERSION = '1.2.1';
|
||||
|
||||
/**
|
||||
* The IoC container for the Flarum application.
|
||||
|
@@ -159,6 +159,9 @@ class InstalledSite implements SiteInterface
|
||||
protected function getIlluminateConfig()
|
||||
{
|
||||
return new ConfigRepository([
|
||||
'app' => [
|
||||
'timezone' => 'UTC'
|
||||
],
|
||||
'view' => [
|
||||
'paths' => [],
|
||||
'compiled' => $this->paths->storage.'/views',
|
||||
@@ -174,7 +177,8 @@ class InstalledSite implements SiteInterface
|
||||
protected function registerLogger(Container $container)
|
||||
{
|
||||
$logPath = $this->paths->storage.'/logs/flarum.log';
|
||||
$handler = new RotatingFileHandler($logPath, 0, Logger::INFO);
|
||||
$logLevel = $this->config->inDebugMode() ? Logger::DEBUG : Logger::INFO;
|
||||
$handler = new RotatingFileHandler($logPath, 0, $logLevel);
|
||||
$handler->setFormatter(new LineFormatter(null, null, true, true));
|
||||
|
||||
$container->instance('log', new Logger('flarum', [$handler]));
|
||||
|
33
src/Mail/FlarumLogTransport.php
Normal file
33
src/Mail/FlarumLogTransport.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Flarum.
|
||||
*
|
||||
* For detailed copyright and license information, please view the
|
||||
* LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Mail;
|
||||
|
||||
use Illuminate\Mail\Transport\LogTransport;
|
||||
use Swift_Mime_SimpleMessage;
|
||||
|
||||
class FlarumLogTransport extends LogTransport
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function send(Swift_Mime_SimpleMessage $message, &$failedRecipients = null)
|
||||
{
|
||||
$this->beforeSendPerformed($message);
|
||||
|
||||
// Overriden to use info, so the log driver works in non-debug mode.
|
||||
$this->logger->info($this->getMimeEntityString($message));
|
||||
|
||||
$this->sendPerformed($message);
|
||||
|
||||
return $this->numberOfRecipients($message);
|
||||
}
|
||||
}
|
@@ -11,7 +11,6 @@ namespace Flarum\Mail;
|
||||
|
||||
use Flarum\Settings\SettingsRepositoryInterface;
|
||||
use Illuminate\Contracts\Validation\Factory;
|
||||
use Illuminate\Mail\Transport\LogTransport;
|
||||
use Illuminate\Support\MessageBag;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Swift_Transport;
|
||||
@@ -45,6 +44,6 @@ class LogDriver implements DriverInterface
|
||||
|
||||
public function buildTransport(SettingsRepositoryInterface $settings): Swift_Transport
|
||||
{
|
||||
return new LogTransport($this->logger);
|
||||
return new FlarumLogTransport($this->logger);
|
||||
}
|
||||
}
|
||||
|
0
tests/fixtures/.gitkeep
vendored
Normal file
0
tests/fixtures/.gitkeep
vendored
Normal file
0
tests/unit/.gitkeep
Normal file
0
tests/unit/.gitkeep
Normal file
Reference in New Issue
Block a user