The default XHR error handler produce an alert which is appropriate to the response status code. It can be overridden per-request (by specifying the `errorHandler` option) so that the alert can be suppressed or displayed in a different position (e.g. inside a modal).
ref #118
We now use Symfony's Translation component. Yay! We get more powerful pluralisation and better a fallback mechanism. Will want to implement the caching mechanism at some point too. The API is replicated in JavaScript, which could definitely use some testing.
Validators have been refactored so that they are decoupled from models completely (i.e. they simply validate arrays of user input). Language packs should include Laravel's validation messages.
ref #267
Falls back to a less effective minification library if ClosureCompilerService errors or is unavailable. Minification takes a while (20 seconds or so), but it only happens when assets are modified. Still, this means enabling/disabling extensions is taking far too long. Possible solutions:
- Don't minify initially; set a process running in the background to do minification, and server unminified assets in the meantime.
- Refactor compiler to send each JS file to CCS individually, only if that particular file has been modified.
flarum/gulp has also been updated to no longer support uglification.
closes#582
- Reorganised all namespaces and class names for consistency and structure. Following PSR bylaws (Abstract prefix, Interface/Trait suffix).
- Move models into root of Core, because writing `use Flarum\Core\Discussion` is nice. Namespace the rest by type. (Namespacing by entity was too arbitrary.)
- Moved some non-domain stuff out of Core: Database, Formatter, Settings.
- Renamed config table and all references to "settings" for consistency.
- Remove Core class and add url()/isInstalled()/inDebugMode() as instance methods of Foundation\Application.
- Cleanup, docblocking, etc.
- Improvements to HTTP architecture
- API and forum/admin Actions are now actually all the same thing (simple PSR-7 Request handlers), renamed to Controllers.
- Upgrade to tobscure/json-api 0.2 branch.
- Where possible, moved generic functionality to tobscure/json-api (e.g. pagination links). I'm quite happy with the backend balance now re: #262
- Improvements to other architecture
- Use Illuminate's Auth\Access\Gate interface/implementation instead of our old Locked trait. We still use events to actually determine the permissions though. Our Policy classes are actually glorified event subscribers.
- Extract model validation into Core\Validator classes.
- Make post visibility permission stuff much more efficient and DRY.
- Renamed Flarum\Event classes for consistency. ref #246
- `Configure` prefix for events dedicated to configuring an object.
- `Get` prefix for events whose listeners should return something.
- `Prepare` prefix when a variable is passed by reference so it can be modified.
- `Scope` prefix when a query builder is passed.
- Miscellaneous improvements/bug-fixes. I'm easily distracted!
- Increase default height of post composer.
- Improve post stream redraw flickering in Safari by keying loading post placeholders with their IDs. ref #451
- Use a PHP JavaScript minification library for minifying TextFormatter's JavaScript, instead of ClosureCompilerService (can't rely on external service!)
- Use UrlGenerator properly in various places. closes#123
- Make Api\Client return Response object. closes#128
- Allow extensions to specify custom icon images.
- Allow external API/admin URLs to be optionally specified in config.php. If the value or "url" is an array, we look for the corresponding path inside. Otherwise, we append the path to the base URL, using the corresponding value in "paths" if present. closes#244
Adds app.trans calls for a couple strings in core:
- The "there are no discussions" message in DiscussionList.js
- The user deletion confirmation message in UserControls.js
- Also adds new HTML-style tags to LogInModal.js and SignUpModal.js
Previously, clicking the "mark all notifications as read" button would individually mark each of the visible notifications as read. Since we now always show a badge with the number of unread notifications, we need to make sure that all notifications (not just the visible ones) can be marked as read. Otherwise it would be possible to get stuck with an unread badge there.
This commit adds a new API endpoint which marks *all* of a user's notifications as read. The JSON-API spec doesn't cover this kind of thing (updating all instances of a certain resource type), so I'm a bit unsure regarding what the endpoint should actually be. For now I've gone with POST /notifications/read, but I'm open to suggestions.
ref #500
Welp, this is probably the most subtle bug I've ever tracked down and fixed.
Turns out that IE has this bug where the "oninput" event will be triggered whenever the "placeholder" attribute is changed. Most placeholders get their value from app.trans. The app.trans method returns a VirtualElement – which is an array, not a string! That means when Mithril's diffing algorithm was comparing the old value to the new value, it was comparing two different array instances, and thus deciding the value was dirty and the placeholder attribute needed to be updated. Due to the IE bug, that was leading to the "oninput" event being triggered... and then through Mithril's auto-redraw mechanism, a redraw would be triggered, and so the cycle continued.
Since the inputs in the LogInModal (among others) only update the component state on the "onchange" event (i.e. when the input loses focus), the intermittent redraws would cause the input's value to be cleared continuously. That's what was causing #464. Could've been easily and superficially patched by changing them to use "oninput" events, but luckily I dived a little deeper!
Glad that's over. Running IE11's buggy dev tools in an underpowered VM isn't fun. Would not recommend.
closes#464
Improved consistency for existing core translation key names.
See flarum/core#265
- Completely overhauled core en.yml
- Replaced existing key names in all core JS files to match
- Extracted a hardcoded string in IndexPage.js
- Combined two app.trans calls in DiscussionControls.js
- Removed hardcoded spaces from LogInModal.js and SignUpModal.js
- Added two new keys from DiscussionControls.js (soft delete)
- Created two new “reused keys” to YML to accommodate same
Enables quick bidirectional bindings. So instead of this:
<input value={prop()} oninput={m.withAttr('value', prop)}/>
... we can do this:
<input bidi={prop}/>
Also add an API to let extensions define additional default route
options.
Allowing default routes with parameters (e.g. /d/123) is very difficult
because of the way Mithril routing works, and it doesn't have a
convincing use-case to justify the trouble. So I've removed the custom
input altogether.
closes#427
Some providers (e.g. Twitter) don't expose user email addresses, so it
turns out we can't use that as the sole form of identification/account
matching.
This commit introduces a new `auth_tokens` table which stores arbitrary
attributes during the sign up process. For example, when Twitter is
authenticated, a new auth token containing the user's Twitter ID will
be created. When sign up is completed with this token, that Twitter ID
will be set as an attribute on the user's account.
Anti-spam extensions may automatically hide the first post in a
discussion, and thus we had to implement smarter permissions so
discussions with zero posts wouldn't be visible to users other than the
author/mods. This change allows those hidden posts to be restored again.
We might consider extracting this into an extension, but TextFormatter
does syntax highlighting for code blocks by default in live previews
anyway.
closes#248
And redirect to the "no JS" mode if the JS app crashes on boot.
ClientView/ClientAction is all a bit of a mess and will need to be
radically cleaned up at some point...
The activity system we were using was built around a separate table.
Whenever the user posted something, or deleted a post, we would sync
the table. The advantage of this was that we could aggregate activity
of all different types very efficiently.
It turns out that it came with a huge disadvantage: there was no
efficient way to enforce permissions on activity. If a user posted
something in a private tag, everyone could still see it on their
activity feed. My stopgap solution was to only sync activity for posts
that are viewable by guests, but that was way too limited.
It also turns out that aggregating activity of different types is
really not that useful, especially considering most of it is the user
making posts. So I've gotten rid of that whole overly-complicated
system, and just made the user profile display separate lists of posts
and discussions, retrieved from those respective APIs. The discussions
page is an actual discussion list too, which is pretty cool.
It's still technically possible to aggregate different activity types
(basically just aggregate API responses together), but we can do that
later if there's a need for it.
This is probably my favourite commit of the day :)
- Fix composer crashing/not showing alert on error
- Make a general ValidationException which takes an array of field ⇒
messages to be outputted nicely by the API