mirror of
https://github.com/flarum/core.git
synced 2025-07-16 22:31:18 +02:00
feat: frontend Model
extender (#3646)
* feat: reintroduce frontend extenders * chore: used `Routes` extender in bundled extensions * chore: used `PostTypes` extender in bundled extensions * chore: `yarn format` * feat: `Model` frontend extender * chore: naming * chore(review): attributes can be nullable or undefined * chore(review): delay extender implementation * chore(review): unnecessary check * chore(review): stay consistent * chore: merge conflicts * chore: unused import * chore: multiline extenders * feat: add Store extender Signed-off-by: Sami Mazouz <sychocouldy@gmail.com>
This commit is contained in:
@@ -18,7 +18,7 @@ trim_trailing_whitespace = false
|
|||||||
[*.{php,xml,json}]
|
[*.{php,xml,json}]
|
||||||
indent_size = 4
|
indent_size = 4
|
||||||
|
|
||||||
[tsconfig.json]
|
[{tsconfig.json,prettierrc.json}]
|
||||||
indent_size = 2
|
indent_size = 2
|
||||||
|
|
||||||
[*.neon]
|
[*.neon]
|
||||||
|
@@ -1,4 +1,16 @@
|
|||||||
import Extend from 'flarum/common/extenders';
|
import Extend from 'flarum/common/extenders';
|
||||||
|
import Post from 'flarum/common/models/Post';
|
||||||
import FlagsPage from './components/FlagsPage';
|
import FlagsPage from './components/FlagsPage';
|
||||||
|
import Flag from './models/Flag';
|
||||||
|
|
||||||
export default [new Extend.Routes().add('flags', '/flags', FlagsPage)];
|
export default [
|
||||||
|
new Extend.Routes() //
|
||||||
|
.add('flags', '/flags', FlagsPage),
|
||||||
|
|
||||||
|
new Extend.Store() //
|
||||||
|
.add('flags', Flag),
|
||||||
|
|
||||||
|
new Extend.Model(Post) //
|
||||||
|
.hasMany<Flag>('flags')
|
||||||
|
.attribute<boolean>('canFlag'),
|
||||||
|
];
|
||||||
|
@@ -1,8 +1,5 @@
|
|||||||
import app from 'flarum/forum/app';
|
import app from 'flarum/forum/app';
|
||||||
import Model from 'flarum/common/Model';
|
|
||||||
|
|
||||||
import Flag from './models/Flag';
|
|
||||||
import FlagsPage from './components/FlagsPage';
|
|
||||||
import FlagListState from './states/FlagListState';
|
import FlagListState from './states/FlagListState';
|
||||||
import addFlagControl from './addFlagControl';
|
import addFlagControl from './addFlagControl';
|
||||||
import addFlagsDropdown from './addFlagsDropdown';
|
import addFlagsDropdown from './addFlagsDropdown';
|
||||||
@@ -11,11 +8,6 @@ import addFlagsToPosts from './addFlagsToPosts';
|
|||||||
export { default as extend } from './extend';
|
export { default as extend } from './extend';
|
||||||
|
|
||||||
app.initializers.add('flarum-flags', () => {
|
app.initializers.add('flarum-flags', () => {
|
||||||
Post.prototype.flags = Model.hasMany<Flag>('flags');
|
|
||||||
Post.prototype.canFlag = Model.attribute<boolean>('canFlag');
|
|
||||||
|
|
||||||
app.store.models.flags = Flag;
|
|
||||||
|
|
||||||
app.flags = new FlagListState(app);
|
app.flags = new FlagListState(app);
|
||||||
|
|
||||||
addFlagControl();
|
addFlagControl();
|
||||||
@@ -26,6 +18,5 @@ app.initializers.add('flarum-flags', () => {
|
|||||||
// Expose compat API
|
// Expose compat API
|
||||||
import flagsCompat from './compat';
|
import flagsCompat from './compat';
|
||||||
import { compat } from '@flarum/core/forum';
|
import { compat } from '@flarum/core/forum';
|
||||||
import Post from 'flarum/common/models/Post';
|
|
||||||
|
|
||||||
Object.assign(compat, flagsCompat);
|
Object.assign(compat, flagsCompat);
|
||||||
|
@@ -1,4 +1,13 @@
|
|||||||
import Extend from 'flarum/common/extenders';
|
import Extend from 'flarum/common/extenders';
|
||||||
|
import Post from 'flarum/common/models/Post';
|
||||||
|
import User from 'flarum/common/models/User';
|
||||||
import LikesUserPage from './components/LikesUserPage';
|
import LikesUserPage from './components/LikesUserPage';
|
||||||
|
|
||||||
export default [new Extend.Routes().add('user.likes', '/u/:username/likes', LikesUserPage)];
|
export default [
|
||||||
|
new Extend.Routes() //
|
||||||
|
.add('user.likes', '/u/:username/likes', LikesUserPage),
|
||||||
|
|
||||||
|
new Extend.Model(Post) //
|
||||||
|
.hasMany<User>('likes')
|
||||||
|
.attribute<boolean>('canLike'),
|
||||||
|
];
|
||||||
|
@@ -1,7 +1,5 @@
|
|||||||
import { extend } from 'flarum/common/extend';
|
import { extend } from 'flarum/common/extend';
|
||||||
import app from 'flarum/forum/app';
|
import app from 'flarum/forum/app';
|
||||||
import Post from 'flarum/common/models/Post';
|
|
||||||
import Model from 'flarum/common/Model';
|
|
||||||
import NotificationGrid from 'flarum/forum/components/NotificationGrid';
|
import NotificationGrid from 'flarum/forum/components/NotificationGrid';
|
||||||
|
|
||||||
import addLikeAction from './addLikeAction';
|
import addLikeAction from './addLikeAction';
|
||||||
@@ -14,9 +12,6 @@ export { default as extend } from './extend';
|
|||||||
app.initializers.add('flarum-likes', () => {
|
app.initializers.add('flarum-likes', () => {
|
||||||
app.notificationComponents.postLiked = PostLikedNotification;
|
app.notificationComponents.postLiked = PostLikedNotification;
|
||||||
|
|
||||||
Post.prototype.canLike = Model.attribute('canLike');
|
|
||||||
Post.prototype.likes = Model.hasMany('likes');
|
|
||||||
|
|
||||||
addLikeAction();
|
addLikeAction();
|
||||||
addLikesList();
|
addLikesList();
|
||||||
addLikesTabToUserProfile();
|
addLikesTabToUserProfile();
|
||||||
|
@@ -1,4 +1,12 @@
|
|||||||
import Extend from 'flarum/common/extenders';
|
import Extend from 'flarum/common/extenders';
|
||||||
|
import Discussion from 'flarum/common/models/Discussion';
|
||||||
import DiscussionLockedPost from './components/DiscussionLockedPost';
|
import DiscussionLockedPost from './components/DiscussionLockedPost';
|
||||||
|
|
||||||
export default [new Extend.PostTypes().add('discussionLocked', DiscussionLockedPost)];
|
export default [
|
||||||
|
new Extend.PostTypes() //
|
||||||
|
.add('discussionLocked', DiscussionLockedPost),
|
||||||
|
|
||||||
|
new Extend.Model(Discussion) //
|
||||||
|
.attribute<boolean>('isLocked')
|
||||||
|
.attribute<boolean>('canLock'),
|
||||||
|
];
|
||||||
|
@@ -1,7 +1,5 @@
|
|||||||
import { extend } from 'flarum/common/extend';
|
import { extend } from 'flarum/common/extend';
|
||||||
import app from 'flarum/forum/app';
|
import app from 'flarum/forum/app';
|
||||||
import Model from 'flarum/common/Model';
|
|
||||||
import Discussion from 'flarum/common/models/Discussion';
|
|
||||||
import NotificationGrid from 'flarum/forum/components/NotificationGrid';
|
import NotificationGrid from 'flarum/forum/components/NotificationGrid';
|
||||||
|
|
||||||
import DiscussionLockedNotification from './components/DiscussionLockedNotification';
|
import DiscussionLockedNotification from './components/DiscussionLockedNotification';
|
||||||
@@ -13,9 +11,6 @@ export { default as extend } from './extend';
|
|||||||
app.initializers.add('flarum-lock', () => {
|
app.initializers.add('flarum-lock', () => {
|
||||||
app.notificationComponents.discussionLocked = DiscussionLockedNotification;
|
app.notificationComponents.discussionLocked = DiscussionLockedNotification;
|
||||||
|
|
||||||
Discussion.prototype.isLocked = Model.attribute('isLocked');
|
|
||||||
Discussion.prototype.canLock = Model.attribute('canLock');
|
|
||||||
|
|
||||||
addLockBadge();
|
addLockBadge();
|
||||||
addLockControl();
|
addLockControl();
|
||||||
|
|
||||||
|
@@ -1,7 +1,5 @@
|
|||||||
import app from 'flarum/forum/app';
|
import app from 'flarum/forum/app';
|
||||||
import { extend } from 'flarum/common/extend';
|
import { extend } from 'flarum/common/extend';
|
||||||
import Model from 'flarum/common/Model';
|
|
||||||
import Post from 'flarum/common/models/Post';
|
|
||||||
import CommentPost from 'flarum/forum/components/CommentPost';
|
import CommentPost from 'flarum/forum/components/CommentPost';
|
||||||
import Link from 'flarum/common/components/Link';
|
import Link from 'flarum/common/components/Link';
|
||||||
import PostPreview from 'flarum/forum/components/PostPreview';
|
import PostPreview from 'flarum/forum/components/PostPreview';
|
||||||
@@ -10,8 +8,6 @@ import username from 'flarum/common/helpers/username';
|
|||||||
import icon from 'flarum/common/helpers/icon';
|
import icon from 'flarum/common/helpers/icon';
|
||||||
|
|
||||||
export default function addMentionedByList() {
|
export default function addMentionedByList() {
|
||||||
Post.prototype.mentionedBy = Model.hasMany('mentionedBy');
|
|
||||||
|
|
||||||
function hidePreview() {
|
function hidePreview() {
|
||||||
this.$('.Post-mentionedBy-preview')
|
this.$('.Post-mentionedBy-preview')
|
||||||
.removeClass('in')
|
.removeClass('in')
|
||||||
|
@@ -1,4 +1,15 @@
|
|||||||
import Extend from 'flarum/common/extenders';
|
import Extend from 'flarum/common/extenders';
|
||||||
|
import Post from 'flarum/common/models/Post';
|
||||||
|
import User from 'flarum/common/models/User';
|
||||||
import MentionsUserPage from './components/MentionsUserPage';
|
import MentionsUserPage from './components/MentionsUserPage';
|
||||||
|
|
||||||
export default [new Extend.Routes().add('user.mentions', '/u/:username/mentions', MentionsUserPage)];
|
export default [
|
||||||
|
new Extend.Routes() //
|
||||||
|
.add('user.mentions', '/u/:username/mentions', MentionsUserPage),
|
||||||
|
|
||||||
|
new Extend.Model(Post) //
|
||||||
|
.hasMany<Post>('mentionedBy'),
|
||||||
|
|
||||||
|
new Extend.Model(User) //
|
||||||
|
.attribute<boolean>('canMentionGroups'),
|
||||||
|
];
|
||||||
|
@@ -21,8 +21,6 @@ import Model from 'flarum/common/Model';
|
|||||||
export { default as extend } from './extend';
|
export { default as extend } from './extend';
|
||||||
|
|
||||||
app.initializers.add('flarum-mentions', function () {
|
app.initializers.add('flarum-mentions', function () {
|
||||||
User.prototype.canMentionGroups = Model.attribute('canMentionGroups');
|
|
||||||
|
|
||||||
// For every mention of a post inside a post's content, set up a hover handler
|
// For every mention of a post inside a post's content, set up a hover handler
|
||||||
// that shows a preview of the mentioned post.
|
// that shows a preview of the mentioned post.
|
||||||
addPostMentionPreviews();
|
addPostMentionPreviews();
|
||||||
|
7
extensions/nicknames/js/src/forum/extend.ts
Normal file
7
extensions/nicknames/js/src/forum/extend.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import Extend from 'flarum/common/extenders';
|
||||||
|
import User from 'flarum/common/models/User';
|
||||||
|
|
||||||
|
export default [
|
||||||
|
new Extend.Model(User) //
|
||||||
|
.attribute<boolean>('canEditNickname'),
|
||||||
|
];
|
@@ -4,15 +4,13 @@ import Button from 'flarum/common/components/Button';
|
|||||||
import EditUserModal from 'flarum/common/components/EditUserModal';
|
import EditUserModal from 'flarum/common/components/EditUserModal';
|
||||||
import SignUpModal from 'flarum/forum/components/SignUpModal';
|
import SignUpModal from 'flarum/forum/components/SignUpModal';
|
||||||
import SettingsPage from 'flarum/forum/components/SettingsPage';
|
import SettingsPage from 'flarum/forum/components/SettingsPage';
|
||||||
import Model from 'flarum/common/Model';
|
|
||||||
import User from 'flarum/common/models/User';
|
|
||||||
import extractText from 'flarum/common/utils/extractText';
|
import extractText from 'flarum/common/utils/extractText';
|
||||||
import Stream from 'flarum/common/utils/Stream';
|
import Stream from 'flarum/common/utils/Stream';
|
||||||
import NickNameModal from './components/NicknameModal';
|
import NickNameModal from './components/NicknameModal';
|
||||||
|
|
||||||
app.initializers.add('flarum/nicknames', () => {
|
export { default as extend } from './extend';
|
||||||
User.prototype.canEditNickname = Model.attribute('canEditNickname');
|
|
||||||
|
|
||||||
|
app.initializers.add('flarum/nicknames', () => {
|
||||||
extend(SettingsPage.prototype, 'accountItems', function (items) {
|
extend(SettingsPage.prototype, 'accountItems', function (items) {
|
||||||
if (app.forum.attribute('displayNameDriver') !== 'nickname') return;
|
if (app.forum.attribute('displayNameDriver') !== 'nickname') return;
|
||||||
|
|
||||||
|
20
extensions/nicknames/js/tsconfig.json
Normal file
20
extensions/nicknames/js/tsconfig.json
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
// Use Flarum's tsconfig as a starting point
|
||||||
|
"extends": "flarum-tsconfig",
|
||||||
|
// This will match all .ts, .tsx, .d.ts, .js, .jsx files in your `src` folder
|
||||||
|
// and also tells your Typescript server to read core's global typings for
|
||||||
|
// access to `dayjs` and `$` in the global namespace.
|
||||||
|
"include": ["src/**/*", "../../../framework/core/js/dist-typings/@types/**/*", "@types/**/*"],
|
||||||
|
"compilerOptions": {
|
||||||
|
// This will output typings to `dist-typings`
|
||||||
|
"declarationDir": "./dist-typings",
|
||||||
|
"paths": {
|
||||||
|
"flarum/*": ["../../../framework/core/js/dist-typings/*"],
|
||||||
|
// TODO: remove after export registry system implemented
|
||||||
|
// Without this, the old-style `@flarum/core` import is resolved to
|
||||||
|
// source code in flarum/core instead of the dist typings.
|
||||||
|
// This causes an inaccurate "duplicate export" error.
|
||||||
|
"@flarum/core/*": ["../../../framework/core/js/dist-typings/*"],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -1,4 +1,12 @@
|
|||||||
import Extend from 'flarum/common/extenders';
|
import Extend from 'flarum/common/extenders';
|
||||||
|
import Discussion from 'flarum/common/models/Discussion';
|
||||||
import DiscussionStickiedPost from './components/DiscussionStickiedPost';
|
import DiscussionStickiedPost from './components/DiscussionStickiedPost';
|
||||||
|
|
||||||
export default [new Extend.PostTypes().add('discussionStickied', DiscussionStickiedPost)];
|
export default [
|
||||||
|
new Extend.PostTypes() //
|
||||||
|
.add('discussionStickied', DiscussionStickiedPost),
|
||||||
|
|
||||||
|
new Extend.Model(Discussion) //
|
||||||
|
.attribute<boolean>('isSticky')
|
||||||
|
.attribute<boolean>('canSticky'),
|
||||||
|
];
|
||||||
|
@@ -1,6 +1,4 @@
|
|||||||
import app from 'flarum/forum/app';
|
import app from 'flarum/forum/app';
|
||||||
import Model from 'flarum/common/Model';
|
|
||||||
import Discussion from 'flarum/common/models/Discussion';
|
|
||||||
|
|
||||||
import addStickyBadge from './addStickyBadge';
|
import addStickyBadge from './addStickyBadge';
|
||||||
import addStickyControl from './addStickyControl';
|
import addStickyControl from './addStickyControl';
|
||||||
@@ -10,9 +8,6 @@ import addStickyClass from './addStickyClass';
|
|||||||
export { default as extend } from './extend';
|
export { default as extend } from './extend';
|
||||||
|
|
||||||
app.initializers.add('flarum-sticky', () => {
|
app.initializers.add('flarum-sticky', () => {
|
||||||
Discussion.prototype.isSticky = Model.attribute('isSticky');
|
|
||||||
Discussion.prototype.canSticky = Model.attribute('canSticky');
|
|
||||||
|
|
||||||
addStickyBadge();
|
addStickyBadge();
|
||||||
addStickyControl();
|
addStickyControl();
|
||||||
addStickyExcerpt();
|
addStickyExcerpt();
|
||||||
|
@@ -1,4 +1,11 @@
|
|||||||
import Extend from 'flarum/common/extenders';
|
import Extend from 'flarum/common/extenders';
|
||||||
import IndexPage from 'flarum/forum/components/IndexPage';
|
import IndexPage from 'flarum/forum/components/IndexPage';
|
||||||
|
import Discussion from 'flarum/common/models/Discussion';
|
||||||
|
|
||||||
export default [new Extend.Routes().add('following', '/following', IndexPage)];
|
export default [
|
||||||
|
new Extend.Routes() //
|
||||||
|
.add('following', '/following', IndexPage),
|
||||||
|
|
||||||
|
new Extend.Model(Discussion) //
|
||||||
|
.attribute('subscription'),
|
||||||
|
];
|
||||||
|
@@ -16,8 +16,6 @@ export { default as extend } from './extend';
|
|||||||
app.initializers.add('subscriptions', function () {
|
app.initializers.add('subscriptions', function () {
|
||||||
app.notificationComponents.newPost = NewPostNotification;
|
app.notificationComponents.newPost = NewPostNotification;
|
||||||
|
|
||||||
Discussion.prototype.subscription = Model.attribute('subscription');
|
|
||||||
|
|
||||||
addSubscriptionBadge();
|
addSubscriptionBadge();
|
||||||
addSubscriptionControls();
|
addSubscriptionControls();
|
||||||
addSubscriptionFilter();
|
addSubscriptionFilter();
|
||||||
|
11
extensions/suspend/js/src/forum/extend.ts
Normal file
11
extensions/suspend/js/src/forum/extend.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import Extend from 'flarum/common/extenders';
|
||||||
|
import User from 'flarum/common/models/User';
|
||||||
|
import Model from 'flarum/common/Model';
|
||||||
|
|
||||||
|
export default [
|
||||||
|
new Extend.Model(User)
|
||||||
|
.attribute<boolean>('canSuspend')
|
||||||
|
.attribute<Date, string | null | undefined>('suspendedUntil', Model.transformDate)
|
||||||
|
.attribute<string | null | undefined>('suspendReason')
|
||||||
|
.attribute<string | null | undefined>('suspendMessage'),
|
||||||
|
];
|
@@ -3,7 +3,6 @@ import app from 'flarum/app';
|
|||||||
import UserControls from 'flarum/utils/UserControls';
|
import UserControls from 'flarum/utils/UserControls';
|
||||||
import Button from 'flarum/components/Button';
|
import Button from 'flarum/components/Button';
|
||||||
import Badge from 'flarum/components/Badge';
|
import Badge from 'flarum/components/Badge';
|
||||||
import Model from 'flarum/Model';
|
|
||||||
import User from 'flarum/models/User';
|
import User from 'flarum/models/User';
|
||||||
|
|
||||||
import SuspendUserModal from './components/SuspendUserModal';
|
import SuspendUserModal from './components/SuspendUserModal';
|
||||||
@@ -11,15 +10,12 @@ import UserSuspendedNotification from './components/UserSuspendedNotification';
|
|||||||
import UserUnsuspendedNotification from './components/UserUnsuspendedNotification';
|
import UserUnsuspendedNotification from './components/UserUnsuspendedNotification';
|
||||||
import checkForSuspension from './checkForSuspension';
|
import checkForSuspension from './checkForSuspension';
|
||||||
|
|
||||||
|
export { default as extend } from './extend';
|
||||||
|
|
||||||
app.initializers.add('flarum-suspend', () => {
|
app.initializers.add('flarum-suspend', () => {
|
||||||
app.notificationComponents.userSuspended = UserSuspendedNotification;
|
app.notificationComponents.userSuspended = UserSuspendedNotification;
|
||||||
app.notificationComponents.userUnsuspended = UserUnsuspendedNotification;
|
app.notificationComponents.userUnsuspended = UserUnsuspendedNotification;
|
||||||
|
|
||||||
User.prototype.canSuspend = Model.attribute('canSuspend');
|
|
||||||
User.prototype.suspendedUntil = Model.attribute('suspendedUntil', Model.transformDate);
|
|
||||||
User.prototype.suspendReason = Model.attribute('suspendReason');
|
|
||||||
User.prototype.suspendMessage = Model.attribute('suspendMessage');
|
|
||||||
|
|
||||||
extend(UserControls, 'moderationControls', (items, user) => {
|
extend(UserControls, 'moderationControls', (items, user) => {
|
||||||
if (user.canSuspend()) {
|
if (user.canSuspend()) {
|
||||||
items.add(
|
items.add(
|
||||||
|
20
extensions/suspend/js/tsconfig.json
Normal file
20
extensions/suspend/js/tsconfig.json
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
// Use Flarum's tsconfig as a starting point
|
||||||
|
"extends": "flarum-tsconfig",
|
||||||
|
// This will match all .ts, .tsx, .d.ts, .js, .jsx files in your `src` folder
|
||||||
|
// and also tells your Typescript server to read core's global typings for
|
||||||
|
// access to `dayjs` and `$` in the global namespace.
|
||||||
|
"include": ["src/**/*", "../../../framework/core/js/dist-typings/@types/**/*", "@types/**/*"],
|
||||||
|
"compilerOptions": {
|
||||||
|
// This will output typings to `dist-typings`
|
||||||
|
"declarationDir": "./dist-typings",
|
||||||
|
"paths": {
|
||||||
|
"flarum/*": ["../../../framework/core/js/dist-typings/*"],
|
||||||
|
// TODO: remove after export registry system implemented
|
||||||
|
// Without this, the old-style `@flarum/core` import is resolved to
|
||||||
|
// source code in flarum/core instead of the dist typings.
|
||||||
|
// This causes an inaccurate "duplicate export" error.
|
||||||
|
"@flarum/core/*": ["../../../framework/core/js/dist-typings/*"],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -1,15 +1,15 @@
|
|||||||
import app from 'flarum/admin/app';
|
import app from 'flarum/admin/app';
|
||||||
import Tag from '../common/models/Tag';
|
|
||||||
import addTagsPermissionScope from './addTagsPermissionScope';
|
import addTagsPermissionScope from './addTagsPermissionScope';
|
||||||
import addTagPermission from './addTagPermission';
|
import addTagPermission from './addTagPermission';
|
||||||
import addTagsHomePageOption from './addTagsHomePageOption';
|
import addTagsHomePageOption from './addTagsHomePageOption';
|
||||||
import addTagChangePermission from './addTagChangePermission';
|
import addTagChangePermission from './addTagChangePermission';
|
||||||
|
import addTagSelectionSettingComponent from './addTagSelectionSettingComponent';
|
||||||
import TagsPage from './components/TagsPage';
|
import TagsPage from './components/TagsPage';
|
||||||
import TagListState from '../common/states/TagListState';
|
import TagListState from '../common/states/TagListState';
|
||||||
|
|
||||||
app.initializers.add('flarum-tags', (app) => {
|
export { default as extend } from '../common/extend';
|
||||||
app.store.models.tags = Tag;
|
|
||||||
|
|
||||||
|
app.initializers.add('flarum-tags', (app) => {
|
||||||
app.tagList = new TagListState();
|
app.tagList = new TagListState();
|
||||||
|
|
||||||
app.extensionData.for('flarum-tags').registerPage(TagsPage);
|
app.extensionData.for('flarum-tags').registerPage(TagsPage);
|
||||||
@@ -24,6 +24,5 @@ app.initializers.add('flarum-tags', (app) => {
|
|||||||
// Expose compat API
|
// Expose compat API
|
||||||
import tagsCompat from './compat';
|
import tagsCompat from './compat';
|
||||||
import { compat } from '@flarum/core/admin';
|
import { compat } from '@flarum/core/admin';
|
||||||
import addTagSelectionSettingComponent from './addTagSelectionSettingComponent';
|
|
||||||
|
|
||||||
Object.assign(compat, tagsCompat);
|
Object.assign(compat, tagsCompat);
|
||||||
|
7
extensions/tags/js/src/common/extend.ts
Normal file
7
extensions/tags/js/src/common/extend.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import Extend from 'flarum/common/extenders';
|
||||||
|
import Tag from './models/Tag';
|
||||||
|
|
||||||
|
export default [
|
||||||
|
new Extend.Store() //
|
||||||
|
.add('tags', Tag),
|
||||||
|
];
|
@@ -1,14 +1,25 @@
|
|||||||
import app from 'flarum/forum/app';
|
import app from 'flarum/forum/app';
|
||||||
import Extend from 'flarum/common/extenders';
|
import Extend from 'flarum/common/extenders';
|
||||||
import IndexPage from 'flarum/forum/components/IndexPage';
|
import IndexPage from 'flarum/forum/components/IndexPage';
|
||||||
|
import Discussion from 'flarum/common/models/Discussion';
|
||||||
import DiscussionTaggedPost from './components/DiscussionTaggedPost';
|
import DiscussionTaggedPost from './components/DiscussionTaggedPost';
|
||||||
import TagsPage from './components/TagsPage';
|
import TagsPage from './components/TagsPage';
|
||||||
|
import Tag from '../common/models/Tag';
|
||||||
|
|
||||||
|
import commonExtend from '../common/extend';
|
||||||
|
|
||||||
export default [
|
export default [
|
||||||
new Extend.Routes()
|
...commonExtend,
|
||||||
.add('tags', '/tags', TagsPage)
|
|
||||||
.add('tag', '/t/:tags', IndexPage)
|
new Extend.Routes() //
|
||||||
|
.add('tags', '/tags', TagsPage) //
|
||||||
|
.add('tag', '/t/:tags', IndexPage) //
|
||||||
.helper('tag', (tag) => app.route('tag', { tags: tag.slug() })),
|
.helper('tag', (tag) => app.route('tag', { tags: tag.slug() })),
|
||||||
|
|
||||||
new Extend.PostTypes().add('discussionTagged', DiscussionTaggedPost),
|
new Extend.PostTypes() //
|
||||||
|
.add('discussionTagged', DiscussionTaggedPost),
|
||||||
|
|
||||||
|
new Extend.Model(Discussion) //
|
||||||
|
.hasMany<Tag>('tags') //
|
||||||
|
.attribute<boolean>('canTag'),
|
||||||
];
|
];
|
||||||
|
@@ -1,9 +1,6 @@
|
|||||||
import app from 'flarum/forum/app';
|
import app from 'flarum/forum/app';
|
||||||
import Model from 'flarum/common/Model';
|
|
||||||
import Discussion from 'flarum/common/models/Discussion';
|
|
||||||
|
|
||||||
import TagListState from '../common/states/TagListState';
|
import TagListState from '../common/states/TagListState';
|
||||||
import Tag from '../common/models/Tag';
|
|
||||||
|
|
||||||
import addTagList from './addTagList';
|
import addTagList from './addTagList';
|
||||||
import addTagFilter from './addTagFilter';
|
import addTagFilter from './addTagFilter';
|
||||||
@@ -14,13 +11,8 @@ import addTagComposer from './addTagComposer';
|
|||||||
export { default as extend } from './extend';
|
export { default as extend } from './extend';
|
||||||
|
|
||||||
app.initializers.add('flarum-tags', function () {
|
app.initializers.add('flarum-tags', function () {
|
||||||
app.store.models.tags = Tag;
|
|
||||||
|
|
||||||
app.tagList = new TagListState();
|
app.tagList = new TagListState();
|
||||||
|
|
||||||
Discussion.prototype.tags = Model.hasMany<Tag>('tags');
|
|
||||||
Discussion.prototype.canTag = Model.attribute<boolean>('canTag');
|
|
||||||
|
|
||||||
addTagList();
|
addTagList();
|
||||||
addTagFilter();
|
addTagFilter();
|
||||||
addTagLabels();
|
addTagLabels();
|
||||||
|
@@ -83,9 +83,9 @@ export default class Store {
|
|||||||
* The model registry. A map of resource types to the model class that
|
* The model registry. A map of resource types to the model class that
|
||||||
* should be used to represent resources of that type.
|
* should be used to represent resources of that type.
|
||||||
*/
|
*/
|
||||||
models: Record<string, typeof Model>;
|
models: Record<string, { new (): Model }>;
|
||||||
|
|
||||||
constructor(models: Record<string, typeof Model>) {
|
constructor(models: Record<string, { new (): Model }>) {
|
||||||
this.models = models;
|
this.models = models;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
42
framework/core/js/src/common/extenders/Model.ts
Normal file
42
framework/core/js/src/common/extenders/Model.ts
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
import IExtender, { IExtensionModule } from './IExtender';
|
||||||
|
import Application from '../Application';
|
||||||
|
import ActualModel from '../Model';
|
||||||
|
|
||||||
|
export default class Model implements IExtender {
|
||||||
|
private readonly model: { new (): ActualModel };
|
||||||
|
private callbacks: Array<() => void> = [];
|
||||||
|
|
||||||
|
public constructor(model: { new (): ActualModel }) {
|
||||||
|
this.model = model;
|
||||||
|
}
|
||||||
|
|
||||||
|
public attribute<T, O = unknown>(name: string, transform: ((attr: O) => T) | null = null): Model {
|
||||||
|
this.callbacks.push(() => {
|
||||||
|
this.model.prototype[name] = transform ? ActualModel.attribute<T, O>(name, transform) : ActualModel.attribute<T>(name);
|
||||||
|
});
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public hasOne<M extends ActualModel>(name: string): Model {
|
||||||
|
this.callbacks.push(() => {
|
||||||
|
this.model.prototype[name] = ActualModel.hasOne<M>(name);
|
||||||
|
});
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public hasMany<M extends ActualModel>(name: string): Model {
|
||||||
|
this.callbacks.push(() => {
|
||||||
|
this.model.prototype[name] = ActualModel.hasMany<M>(name);
|
||||||
|
});
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
extend(app: Application, extension: IExtensionModule): void {
|
||||||
|
for (const callback of this.callbacks) {
|
||||||
|
callback.call(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
23
framework/core/js/src/common/extenders/Store.ts
Normal file
23
framework/core/js/src/common/extenders/Store.ts
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import Application from '../Application';
|
||||||
|
import IExtender, { IExtensionModule } from './IExtender';
|
||||||
|
import Model from '../Model';
|
||||||
|
|
||||||
|
export default class Store implements IExtender {
|
||||||
|
private readonly models: { [type: string]: { new (): Model } } = {};
|
||||||
|
|
||||||
|
public add(type: string, model: { new (): Model }): Store {
|
||||||
|
this.models[type] = model;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
extend(app: Application, extension: IExtensionModule): void {
|
||||||
|
for (const type in this.models) {
|
||||||
|
if (app.store.models[type]) {
|
||||||
|
throw new Error(`The model type "${type}" has already been registered with the class "${app.store.models[type].name}".`);
|
||||||
|
}
|
||||||
|
|
||||||
|
app.store.models[type] = this.models[type];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -1,7 +1,11 @@
|
|||||||
|
import Model from './Model';
|
||||||
import PostTypes from './PostTypes';
|
import PostTypes from './PostTypes';
|
||||||
import Routes from './Routes';
|
import Routes from './Routes';
|
||||||
|
import Store from './Store';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
Model,
|
||||||
PostTypes,
|
PostTypes,
|
||||||
Routes,
|
Routes,
|
||||||
|
Store,
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user