- mapRoutes: don't wrap components in resolvers if they are already resolvers
- Extract defaultResolver into its own class
- Allow either route resolver instances, or components with an optional resolverClass which should accept the component and route name in its constructor.
- Introduce a resolver for DiscussionPage, so that routing from one post to another on the same discussion triggers a scroll instead of rerendering
- Add an index to reply placeholder so we can scroll to it directly when replying.
- Stop pretending that the currently broken `bottom` scroll functionality works, and explicitly call it `reply` scrolling to be clearer
- Directly get target from state
- Explicitly scroll to placeholder on reply
- Clean up scrollToItem code a bit
- Account for edge case where index is undefined when scrolling to post
Co-authored-by: Wadim Kalmykov <36057469+w-4@users.noreply.github.com>
Essentially, whenever a route is loaded, we add a key to that component. If the key changes, the page completely rerenders. Switching between different routes handled by the same key triggers those rerenders.
- If the fadeIn animation is specified on the PostStream class itself, any time we add/remove another animation, it will redo fadeIn. To avoid this, we move fadeIn into it's own css class, which is applied, and then immediately removed after the animation is completed to ensure it only runs once.
- The "fix" for flashItem was actually broken, as it resulted in 'flash' never being removed, so we never went back to .PostStream's fadeIn. We adjust flashItem to ensure that '.flash' is removed. We also remove 'fadeIn' in case it hasn't yet been removed in oncreate.
Make header and navigation components redraw after page components. Page components manipulate the header (state), but the header redraws before the page on route change. By changing the mount order, we change also the redraw order.
If the error isn't a 409, we'll want to re-throw the error so it'll be handled by the default system (showing an alert).
For simplicity, we can also move 409-handling logic out of setTimeout.
Finally, we adjust the timeout to 300 milliseconds to match the modal transition animation length.
* Revert "Fix header contents moving when opening modal (#2131)"
* Fix header contents moving when modal opened/closed.
Conditionally apply the navbar-fixed-top class only when needed, so that we can take advantage of it without always having the navbar in position:fixed, as was done in the previous solution. That resulted in a clash with custom headers.
* Show header on refresh of scrolled page
Due to some magic in Mithril 0.1's context:retain flag, some DOM elements were cached across page reloads. Since that has been eliminated, if we refresh the page and we are scrolled down, the "affix" class which makes the header fixed (and as a result, visible) isn't applied until the first scroll. We fix this by running ScrollListener.update() immediately to set initial navbar state.
When on a discussion page, the URL changing doesn't always mean we've moved to a different page. In our custom rerender logic, we only want to call `this.onNewRoute()` if the page has actually changed.
After we scroll to a post, we redraw to render post content. We then update the scrubber again so its height is accurate. This commit moves that update to AFTER our adjustment of scroll position, so that scrubber height is based on actual post heights. This fixes some subtle scrubber glitches.
Let's stay consistent with previous behavior, and run these on "internal route change" (same component handles different route) as well as on initial render of a page component.
Currently, the controls are on a new line due to the container div. We want to wrap ALL children of the alert, including the controls, in the container div.
We need to split it into a separate class so that we can add modify the alert vnode AFTER the alert component's `view` logic has been applied.
From using PhpStorm to try and see if the autocomplete works properly, it appears as it doesn't. The intention was to not have to import Mithril every time we wanted to type something with Mithril.*, but that doesn't seem to be possible - and it's not a big deal anyway
During the frontend rewrite, we introduced mithril patches for a `route` attr, and for `m.stream`. Later, we decided not to go that route, but not to remove the patches yet to avoid breaking extensions while we were finalizing the replacements. We can now remove these.
Other BC layers are for things from before beta 14, so those remain in place.
- Use Mithril.Attributes as base for ComponentAttrs, remove =any from class signature for Component
- Convert Alert to TypeScript, introduce AlertAttrs interface
- Convert AlertManagerState to TypeScript, add overload signatures for `show`, introduce AlertState interface for stored Alerts.
- Set ComponentAttrs as default T for Component
- Make attrs in AlertAttrs optional
- Add AlertIdentifier interface, simplify show type signature
- Remove mithril patch shim, as all patches onto m are now deprecated
- Use Mithril.Static for shim
- Ensure that the discussion list is cleared before it is updated with fetched results
- Rename `clear` to `deferClear`, improve documentation to make its purpose clearer.
- Call onNewRoute when page changed with same component in DiscussionPage and UserPage
- Make app.previous and app.current changed in onNewRoute, not in oninit. This way, when the route is changed, but still handled by the same component, a new PageState object will still be created.
While more pleasant from an FSM standpoint, comparing the current targetPost to the previous one does not work if goToNumber is called twice in a row for the same post. For instance, if a user clicks the mentions link to a post twice, the post stream breaks.
In some cases, such as if we've stickied a post, an event post
may have been added / removed.This means that `this.visibleEnd`
and`this.count()` will be out of sync by 1 post, but we are still
"viewing the end" of the post stream, so we should still reload
all posts up until the last one.
Because the Slidable class was always added on creation, it was lost every time the class list changed (in this case when the discussion was hidden/unhidden which added/removed DiscussionListItem--hidden class). So by determining the Slidable class's presence in elementAttrs() method, it guarantees it always properly set.
While seemingly correct, an onremove method in Modal that triggers animateHide is problematic, because if one modal is opened from another, the one currently open will be removed from the DOM, triggering animateHide, and closing the new modal.
To compensate, an onupdate method now closes a modal if one is open but shouldn't be; this supports the functionality of the old method when the modal is closed not from the modal instance itself (e.g. app.modal.close())
This is not ideal, but necessary. We should consider eventually expanding the modal system to support showing multiple modals at the same time (stacked over each other). Then, we can move this back to individual modals.
When the page is scrolled, goToIndex is called, or the page is loaded,
various listeners result in the scrubber being updated with a new
position and values. However, if goToNumber is called, the scrubber
will not be updated. Accordingly, we add logic to the scrubber's
onupdate to update itself, but only when needed, as indicated by this
This saves us a LOT of unnecessary calls, and makes scrubber movement smoother.
* Update frontend to Mithril 2
- Update Mithril version to v2.0.4
- Add Typescript typings for Mithril
- Rename "props" to "attrs"; "initProps" to "initAttrs"; "m.prop" to "m.stream"; "m.withAttr" to "utils/withAttr".
- Use Mithril 2's new lifecycle hooks
- SubtreeRetainer has been rewritten to be more useful for the new system
- Utils for forcing page re-initializations have been added (force attr in links, setRouteWithForcedRefresh util)
- Other mechanical changes, following the upgrade guide
- Remove some of the custom stuff in our Component base class
- Introduce "fragments" for non-components that control their own DOM
- Remove Mithril patches, introduce a few new ones (route attrs in <a>;
- Redesign AlertManagerState `show` with 3 overloads: `show(children)`, `show(attrs, children)`, `show(componentClass, attrs, children)`
- The `affixedSidebar` util has been replaced with an `AffixedSidebar` component
Challenges:
- `children` and `tag` are now reserved, and can not be used as attr names
- Behavior of links to current page changed in Mithril. If moving to a page that is handled by the same component, the page component WILL NOT be re-initialized by default. Additional code to keep track of the current url is needed (See IndexPage, DiscussionPage, and UserPage for examples)
- Native Promise rejections are shown on console when not handled
- Instances of components can no longer be stored. The state pattern should be used instead.
Refs #1821.
Co-authored-by: Alexander Skvortsov <sasha.skvortsov109@gmail.com>
Co-authored-by: Matthew Kilgore <tankerkiller125@gmail.com>
Co-authored-by: Franz Liedke <franz@develophp.org>
This is needed to have access to the newly created SuperTextarea
instance (app.composer.editor) directly after calling show().
Discovered when making ext-mentions work with the Composer state
changes. As far as I could reconstruct, a synchronous redraw was also
triggered in this situation before the changes in #2161.