mirror of
https://github.com/flarum/core.git
synced 2025-08-01 22:20:21 +02:00
Merge pull request #3228 from flarum/as/v1.2_frontend_fixes
Some v1.2 frontend fixes
This commit is contained in:
@@ -9,6 +9,7 @@ import Translator from './Translator';
|
|||||||
import Store, { ApiPayload, ApiResponse, ApiResponsePlural, ApiResponseSingle, payloadIsPlural } from './Store';
|
import Store, { ApiPayload, ApiResponse, ApiResponsePlural, ApiResponseSingle, payloadIsPlural } from './Store';
|
||||||
import Session from './Session';
|
import Session from './Session';
|
||||||
import extract from './utils/extract';
|
import extract from './utils/extract';
|
||||||
|
import extractText from './utils/extractText';
|
||||||
import Drawer from './utils/Drawer';
|
import Drawer from './utils/Drawer';
|
||||||
import mapRoutes from './utils/mapRoutes';
|
import mapRoutes from './utils/mapRoutes';
|
||||||
import RequestError, { InternalFlarumRequestOptions } from './utils/RequestError';
|
import RequestError, { InternalFlarumRequestOptions } from './utils/RequestError';
|
||||||
@@ -365,9 +366,21 @@ export default class Application {
|
|||||||
|
|
||||||
updateTitle(): void {
|
updateTitle(): void {
|
||||||
const count = this.titleCount ? `(${this.titleCount}) ` : '';
|
const count = this.titleCount ? `(${this.titleCount}) ` : '';
|
||||||
const pageTitleWithSeparator = this.title && m.route.get() !== this.forum.attribute('basePath') + '/' ? this.title + ' - ' : '';
|
const onHomepage = m.route.get() === this.forum.attribute('basePath') + '/';
|
||||||
const title = this.forum.attribute('title');
|
|
||||||
document.title = count + pageTitleWithSeparator + title;
|
const params = {
|
||||||
|
pageTitle: this.title,
|
||||||
|
forumName: this.forum.attribute('title'),
|
||||||
|
// Until we add page numbers to the frontend, this is constant at 1
|
||||||
|
// so that the page number portion doesn't show up in the URL.
|
||||||
|
pageNumber: 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
const title =
|
||||||
|
onHomepage || !this.title
|
||||||
|
? extractText(app.translator.trans('core.lib.meta_titles.without_page_title', params))
|
||||||
|
: extractText(app.translator.trans('core.lib.meta_titles.with_page_title', params));
|
||||||
|
document.title = count + title;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected transformRequestOptions<ResponseType>(flarumOptions: FlarumRequestOptions<ResponseType>): InternalFlarumRequestOptions<ResponseType> {
|
protected transformRequestOptions<ResponseType>(flarumOptions: FlarumRequestOptions<ResponseType>): InternalFlarumRequestOptions<ResponseType> {
|
||||||
|
@@ -24,16 +24,19 @@ export default class ModalManager extends Component<IModalManagerAttrs> {
|
|||||||
|
|
||||||
view(vnode: Mithril.VnodeDOM<IModalManagerAttrs, this>): Mithril.Children {
|
view(vnode: Mithril.VnodeDOM<IModalManagerAttrs, this>): Mithril.Children {
|
||||||
const modal = this.attrs.state.modal;
|
const modal = this.attrs.state.modal;
|
||||||
|
const Tag = modal?.componentClass;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="ModalManager modal fade">
|
<div className="ModalManager modal fade">
|
||||||
{!!modal &&
|
{!!Tag && (
|
||||||
modal.componentClass.component({
|
<Tag
|
||||||
...modal.attrs,
|
key={modal?.key}
|
||||||
animateShow: this.animateShow.bind(this),
|
{...modal.attrs}
|
||||||
animateHide: this.animateHide.bind(this),
|
animateShow={this.animateShow.bind(this)}
|
||||||
state: this.attrs.state,
|
animateHide={this.animateHide.bind(this)}
|
||||||
})}
|
state={this.attrs.state}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -22,8 +22,15 @@ export default class ModalManagerState {
|
|||||||
modal: null | {
|
modal: null | {
|
||||||
componentClass: UnsafeModalClass;
|
componentClass: UnsafeModalClass;
|
||||||
attrs?: Record<string, unknown>;
|
attrs?: Record<string, unknown>;
|
||||||
|
key: number;
|
||||||
} = null;
|
} = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to force re-initialization of modals if a modal
|
||||||
|
* is replaced by another of the same type.
|
||||||
|
*/
|
||||||
|
private key = 0;
|
||||||
|
|
||||||
private closeTimeout?: NodeJS.Timeout;
|
private closeTimeout?: NodeJS.Timeout;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -48,7 +55,7 @@ export default class ModalManagerState {
|
|||||||
|
|
||||||
if (this.closeTimeout) clearTimeout(this.closeTimeout);
|
if (this.closeTimeout) clearTimeout(this.closeTimeout);
|
||||||
|
|
||||||
this.modal = { componentClass, attrs };
|
this.modal = { componentClass, attrs, key: this.key++ };
|
||||||
|
|
||||||
m.redraw.sync();
|
m.redraw.sync();
|
||||||
}
|
}
|
||||||
|
@@ -27,7 +27,10 @@ export default class Drawer {
|
|||||||
});
|
});
|
||||||
|
|
||||||
this.appElement = document.getElementById('app');
|
this.appElement = document.getElementById('app');
|
||||||
this.focusTrap = createFocusTrap('#drawer', { allowOutsideClick: true });
|
// Despite the `focus-trap` documentation, both `clickOutsideDeactivates`
|
||||||
|
// and `allowOutsideClick` are necessary so that inputs in modals triggered
|
||||||
|
// from the drawer's nav components can be interacted with.
|
||||||
|
this.focusTrap = createFocusTrap('#drawer', { allowOutsideClick: true, clickOutsideDeactivates: true });
|
||||||
this.drawerAvailableMediaQuery = window.matchMedia(
|
this.drawerAvailableMediaQuery = window.matchMedia(
|
||||||
`(max-width: ${getComputedStyle(document.documentElement).getPropertyValue('--screen-phone-max')})`
|
`(max-width: ${getComputedStyle(document.documentElement).getPropertyValue('--screen-phone-max')})`
|
||||||
);
|
);
|
||||||
|
@@ -88,7 +88,7 @@ export default class Search<T extends SearchAttrs = SearchAttrs> extends Compone
|
|||||||
/**
|
/**
|
||||||
* An array of SearchSources.
|
* An array of SearchSources.
|
||||||
*/
|
*/
|
||||||
protected sources!: SearchSource[];
|
protected sources?: SearchSource[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The number of sources that are still loading results.
|
* The number of sources that are still loading results.
|
||||||
@@ -192,7 +192,7 @@ export default class Search<T extends SearchAttrs = SearchAttrs> extends Compone
|
|||||||
this.setIndex(this.getCurrentNumericIndex());
|
this.setIndex(this.getCurrentNumericIndex());
|
||||||
|
|
||||||
// If there are no sources, the search view is not shown.
|
// If there are no sources, the search view is not shown.
|
||||||
if (!this.sources.length) return;
|
if (!this.sources?.length) return;
|
||||||
|
|
||||||
this.updateMaxHeight();
|
this.updateMaxHeight();
|
||||||
}
|
}
|
||||||
@@ -200,6 +200,10 @@ export default class Search<T extends SearchAttrs = SearchAttrs> extends Compone
|
|||||||
oncreate(vnode: Mithril.VnodeDOM<T, this>) {
|
oncreate(vnode: Mithril.VnodeDOM<T, this>) {
|
||||||
super.oncreate(vnode);
|
super.oncreate(vnode);
|
||||||
|
|
||||||
|
// If there are no sources, we shouldn't initialize logic for
|
||||||
|
// search elements, as they will not be shown.
|
||||||
|
if (!this.sources?.length) return;
|
||||||
|
|
||||||
const search = this;
|
const search = this;
|
||||||
const state = this.searchState;
|
const state = this.searchState;
|
||||||
|
|
||||||
@@ -237,7 +241,7 @@ export default class Search<T extends SearchAttrs = SearchAttrs> extends Compone
|
|||||||
if (state.isCached(query)) return;
|
if (state.isCached(query)) return;
|
||||||
|
|
||||||
if (query.length >= (search.constructor as typeof Search).MIN_SEARCH_LEN) {
|
if (query.length >= (search.constructor as typeof Search).MIN_SEARCH_LEN) {
|
||||||
search.sources.map((source) => {
|
search.sources?.map((source) => {
|
||||||
if (!source.search) return;
|
if (!source.search) return;
|
||||||
|
|
||||||
search.loadingSources++;
|
search.loadingSources++;
|
||||||
|
@@ -542,6 +542,11 @@ core:
|
|||||||
loading_indicator:
|
loading_indicator:
|
||||||
accessible_label: => core.ref.loading
|
accessible_label: => core.ref.loading
|
||||||
|
|
||||||
|
# Translations in this namespace are used to format page meta titles.
|
||||||
|
meta_titles:
|
||||||
|
with_page_title: "{pageNumber, plural, =1 {{pageTitle} - {forumName}} other {{pageTitle}: Page # - {forumName}}}"
|
||||||
|
without_page_title: "{pageNumber, plural, =1 {{forumName}} other {Page # - {forumName}}}"
|
||||||
|
|
||||||
# These translations are used in modals.
|
# These translations are used in modals.
|
||||||
modal:
|
modal:
|
||||||
close: Close
|
close: Close
|
||||||
@@ -628,11 +633,6 @@ core:
|
|||||||
submit_button: => core.ref.save_changes
|
submit_button: => core.ref.save_changes
|
||||||
title: => core.ref.reset_your_password
|
title: => core.ref.reset_your_password
|
||||||
|
|
||||||
# Translations in this namespace are used to format page meta titles.
|
|
||||||
meta_titles:
|
|
||||||
with_page_title: "{pageNumber, plural, =1 {{pageTitle} - {forumName}} other {{pageTitle}: Page # - {forumName}}}"
|
|
||||||
without_page_title: "{pageNumber, plural, =1 {{forumName}} other {Page # - {forumName}}}"
|
|
||||||
|
|
||||||
# Translations in this namespace are used in messages output by the API.
|
# Translations in this namespace are used in messages output by the API.
|
||||||
api:
|
api:
|
||||||
invalid_username_message: "The username may only contain letters, numbers, and dashes."
|
invalid_username_message: "The username may only contain letters, numbers, and dashes."
|
||||||
|
@@ -37,7 +37,7 @@ class BasicTitleDriver implements TitleDriverInterface
|
|||||||
];
|
];
|
||||||
|
|
||||||
return $onHomePage || ! $document->title
|
return $onHomePage || ! $document->title
|
||||||
? $this->translator->trans('core.views.meta_titles.without_page_title', $params)
|
? $this->translator->trans('core.lib.meta_titles.without_page_title', $params)
|
||||||
: $this->translator->trans('core.views.meta_titles.with_page_title', $params);
|
: $this->translator->trans('core.lib.meta_titles.with_page_title', $params);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user