mirror of
https://github.com/flarum/core.git
synced 2025-08-18 14:22:02 +02:00
Compare commits
17 Commits
dk/info-v2
...
2.x
Author | SHA1 | Date | |
---|---|---|---|
|
a46ce07255 | ||
|
8e404e4415 | ||
|
4e95d06190 | ||
|
e1a91dcd77 | ||
|
fbe7be69ef | ||
|
7f946ca0dd | ||
|
cc05a6dd3b | ||
|
649be7cb03 | ||
|
f19007f424 | ||
|
15112c2f40 | ||
|
00ef0dd9d0 | ||
|
cae706a638 | ||
|
2be1932e54 | ||
|
2339c23aae | ||
|
2b08c30a22 | ||
|
fa88731fe1 | ||
|
65d8c16580 |
42
CHANGELOG.md
42
CHANGELOG.md
@@ -1,5 +1,47 @@
|
||||
# Changelog
|
||||
|
||||
## [v2.0.0-beta.3](https://github.com/flarum/framework/compare/v2.0.0-beta.2...v2.0.0-beta.3)
|
||||
### Changed
|
||||
- (a11y) misc a11y improvements by @SychO9 [#4211]
|
||||
- allow labels of `PostStreamScrubber` to be customized by @DavideIadeluca [#4181]
|
||||
- improve extensibility of Admin Pages by @DavideIadeluca [#4200]
|
||||
- improve extensibility of `IndexPage` by @DavideIadeluca [#4182]
|
||||
- improve extensibility of `PostMeta` component by @DavideIadeluca [#4196]
|
||||
- make search debounce time extensible by @DavideIadeluca [#4172]
|
||||
- Sanitize page in `Tag` (#4170) by @rob006 (15112c2f40656db8c310945e6c7255b90570379f)
|
||||
- Codebase cleanup by @xHeaven [#4161]
|
||||
- `audit-fix` by @SychO9 (fbe7be69ef573d0d39f70454bfd02ab94857db8a)
|
||||
- increase composer job timeout by @SychO9 (fa88731fe1f4473831af6ba56b186c72924307d9)
|
||||
- optimize querying post index by @SychO9 [#4178]
|
||||
- render after first post items once by @SychO9 (973f4f6f6ba8574b9d56674df94a02f060464ca4)
|
||||
- (tags) improve extensibility of `TagHero` by @DavideIadeluca [#4198]
|
||||
- allow extending `PostPreview` content by @DavideIadeluca [#4197]
|
||||
- improve extensibility of `WelcomeHero` by @DavideIadeluca [#4199]
|
||||
- make it easier to add content after the first post by @DavideIadeluca [#4186]
|
||||
### Fixed
|
||||
- (security) Session Hijacking via Authoritative Subdomain Cookie Overwrite by @novacuum (f19007f42466ebf881307670a32d14516444ac24)
|
||||
- fixes issue with smtp non-tls connections by @luceos [#4203]
|
||||
- change condition when `unread` label is shown in Scrubber by @DavideIadeluca [#4185]
|
||||
- change starting position of `aria-posinset` by @DavideIadeluca [#4191]
|
||||
- return empty object if selected mail driver is unavailable by @DavideIadeluca [#4183]
|
||||
- (tags) resolve `a11y` warnings in Admin Frontend by @DavideIadeluca [#4184]
|
||||
- (em) skip incompatible extension updates by @SychO9 [#4177]
|
||||
- (phpstan) incompatibility with recent updates by @SychO9 (1b9ff2b6fa90a9c991b6e1d9ab5bd959802bd099)
|
||||
- (webpack) chunk module path checking fails with dotted directories by @DavideIadeluca [#4179]
|
||||
- `sendmail` driver fails by @SychO9 [#4168]
|
||||
- `suspended_until` serialized as date instead of datetime by @SychO9 [#4169]
|
||||
- messages UI/UX improvement by @SychO9 [#4173]
|
||||
- messages inconsistencies by @SychO9 [#4174]
|
||||
- prevent users from seeing their own flags by @SychO9 [#4167]
|
||||
- visual bugs by @SychO9 (97e56af2cd8e97e4ef10235d3e584d0def2afffc)
|
||||
### Added
|
||||
- (messages) messages page extensible content by @SychO9 (561e22784a547c8aa92120e0972a9cc97ac21645)
|
||||
- (pm) delete own messages by @SychO9 [#4180]
|
||||
- (pm) messages anchor link by @SychO9 [#4175]
|
||||
- actions dropdown in admin user list by @DavideIadeluca [#4188]
|
||||
- advanced admin registry extenders by @SychO9 [#4209]
|
||||
- reusable component for showing IP address by @DavideIadeluca [#4187]
|
||||
|
||||
## [v2.0.0-beta.2](https://github.com/flarum/framework/compare/v2.0.0-beta.1...v2.0.0-beta.2)
|
||||
### Fixed
|
||||
- (em) incorrect extension compatibility check [#4155]
|
||||
|
@@ -19,7 +19,7 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"flarum/core": "^2.0.0-beta.2",
|
||||
"flarum/core": "^2.0.0-beta.3",
|
||||
"flarum/approval": "^2.0"
|
||||
},
|
||||
"autoload": {
|
||||
|
@@ -19,7 +19,7 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"flarum/core": "^2.0.0-beta.2",
|
||||
"flarum/core": "^2.0.0-beta.3",
|
||||
"flarum/flags": "^2.0"
|
||||
},
|
||||
"autoload": {
|
||||
|
2
extensions/approval/js/dist/forum.js
generated
vendored
2
extensions/approval/js/dist/forum.js
generated
vendored
@@ -1,2 +1,2 @@
|
||||
(()=>{var t={n:o=>{var r=o&&o.__esModule?()=>o.default:()=>o;return t.d(r,{a:r}),r},d:(o,r)=>{for(var e in r)t.o(r,e)&&!t.o(o,e)&&Object.defineProperty(o,e,{enumerable:!0,get:r[e]})},o:(t,o)=>Object.prototype.hasOwnProperty.call(t,o)};(()=>{"use strict";const o=flarum.reg.get("core","common/extend"),r=flarum.reg.get("core","forum/app");var e=t.n(r);const a=flarum.reg.get("core","common/models/Discussion");var n=t.n(a);const p=flarum.reg.get("core","common/models/Post");var s=t.n(p);const i=flarum.reg.get("core","common/components/Badge");var c=t.n(i);const u=flarum.reg.get("core","forum/components/DiscussionListItem");var l=t.n(u);const d=flarum.reg.get("core","forum/components/Post");var v=t.n(d);const f=flarum.reg.get("core","forum/components/CommentPost");var g=t.n(f);const A=flarum.reg.get("core","common/components/Button");var h=t.n(A);const b=flarum.reg.get("core","forum/utils/PostControls");var y=t.n(b);e().initializers.add("flarum-approval",(()=>{n().prototype.isApproved=n().attribute("isApproved"),(0,o.extend)(n().prototype,"badges",(function(t){this.isApproved()||t.has("hidden")||t.add("awaitingApproval",m(c(),{type:"awaitingApproval",icon:"fas fa-gavel",label:e().translator.trans("flarum-approval.forum.badge.awaiting_approval_tooltip")}))})),s().prototype.isApproved=s().attribute("isApproved"),s().prototype.canApprove=s().attribute("canApprove"),(0,o.extend)(l().prototype,"elementAttrs",(function(t){this.attrs.discussion.isApproved()||(t.className+=" DiscussionListItem--unapproved")})),(0,o.extend)(v().prototype,"elementAttrs",(function(t){this.attrs.post.isApproved()||(t.className+=" Post--unapproved")})),(0,o.extend)(g().prototype,"headerItems",(function(t){this.attrs.post.isApproved()||this.attrs.post.isHidden()||t.add("unapproved",e().translator.trans("flarum-approval.forum.post.awaiting_approval_text"))})),(0,o.override)(v().prototype,"flagReason",(function(t,o){return"approval"===o.type()?e().translator.trans("flarum-approval.forum.post.awaiting_approval_text"):t(o)})),(0,o.extend)(y(),"destructiveControls",(function(t,o){!o.isApproved()&&o.canApprove()&&t.add("approve",m(h(),{icon:"fas fa-check",onclick:y().approveAction.bind(o)},e().translator.trans("flarum-approval.forum.post_controls.approve_button")),10)})),y().approveAction=function(){this.save({isApproved:!0}),1===this.number()&&this.discussion().pushAttributes({isApproved:!0})}}),-10)})(),module.exports={}})();
|
||||
(()=>{var t={n:o=>{var r=o&&o.__esModule?()=>o.default:()=>o;return t.d(r,{a:r}),r},d:(o,r)=>{for(var e in r)t.o(r,e)&&!t.o(o,e)&&Object.defineProperty(o,e,{enumerable:!0,get:r[e]})},o:(t,o)=>Object.prototype.hasOwnProperty.call(t,o)};(()=>{"use strict";const o=flarum.reg.get("core","common/extend"),r=flarum.reg.get("core","forum/app");var e=t.n(r);const a=flarum.reg.get("core","common/models/Discussion");var n=t.n(a);const p=flarum.reg.get("core","common/models/Post");var s=t.n(p);const i=flarum.reg.get("core","common/components/Badge");var c=t.n(i);const u=flarum.reg.get("core","forum/components/DiscussionListItem");var l=t.n(u);const d=flarum.reg.get("core","forum/components/Post");var v=t.n(d);const f=flarum.reg.get("core","forum/components/CommentPost");var g=t.n(f);const A=flarum.reg.get("core","common/components/Button");var b=t.n(A);const h=flarum.reg.get("core","forum/utils/PostControls");var y=t.n(h);e().initializers.add("flarum-approval",(()=>{n().prototype.isApproved=n().attribute("isApproved"),(0,o.extend)(n().prototype,"badges",(function(t){this.isApproved()||t.has("hidden")||t.add("awaitingApproval",m(c(),{type:"awaitingApproval",icon:"fas fa-gavel",label:e().translator.trans("flarum-approval.forum.badge.awaiting_approval_tooltip"),tabindex:"0"}))})),s().prototype.isApproved=s().attribute("isApproved"),s().prototype.canApprove=s().attribute("canApprove"),(0,o.extend)(l().prototype,"elementAttrs",(function(t){this.attrs.discussion.isApproved()||(t.className+=" DiscussionListItem--unapproved")})),(0,o.extend)(v().prototype,"elementAttrs",(function(t){this.attrs.post.isApproved()||(t.className+=" Post--unapproved")})),(0,o.extend)(g().prototype,"headerItems",(function(t){this.attrs.post.isApproved()||this.attrs.post.isHidden()||t.add("unapproved",e().translator.trans("flarum-approval.forum.post.awaiting_approval_text"))})),(0,o.override)(v().prototype,"flagReason",(function(t,o){return"approval"===o.type()?e().translator.trans("flarum-approval.forum.post.awaiting_approval_text"):t(o)})),(0,o.extend)(y(),"destructiveControls",(function(t,o){!o.isApproved()&&o.canApprove()&&t.add("approve",m(b(),{icon:"fas fa-check",onclick:y().approveAction.bind(o)},e().translator.trans("flarum-approval.forum.post_controls.approve_button")),10)})),y().approveAction=function(){this.save({isApproved:!0}),1===this.number()&&this.discussion().pushAttributes({isApproved:!0})}}),-10)})(),module.exports={}})();
|
||||
//# sourceMappingURL=forum.js.map
|
2
extensions/approval/js/dist/forum.js.map
generated
vendored
2
extensions/approval/js/dist/forum.js.map
generated
vendored
File diff suppressed because one or more lines are too long
@@ -18,7 +18,12 @@ app.initializers.add(
|
||||
if (!this.isApproved() && !items.has('hidden')) {
|
||||
items.add(
|
||||
'awaitingApproval',
|
||||
<Badge type="awaitingApproval" icon="fas fa-gavel" label={app.translator.trans('flarum-approval.forum.badge.awaiting_approval_tooltip')} />
|
||||
<Badge
|
||||
type="awaitingApproval"
|
||||
icon="fas fa-gavel"
|
||||
label={app.translator.trans('flarum-approval.forum.badge.awaiting_approval_tooltip')}
|
||||
tabindex="0"
|
||||
/>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
@@ -19,7 +19,7 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"flarum/core": "^2.0.0-beta.2"
|
||||
"flarum/core": "^2.0.0-beta.3"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
|
@@ -19,7 +19,7 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"flarum/core": "^2.0.0-beta.2"
|
||||
"flarum/core": "^2.0.0-beta.3"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
|
@@ -19,7 +19,7 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"flarum/core": "^2.0.0-beta.2"
|
||||
"flarum/core": "^2.0.0-beta.3"
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
2
extensions/emoji/js/dist/forum.js
generated
vendored
2
extensions/emoji/js/dist/forum.js
generated
vendored
File diff suppressed because one or more lines are too long
2
extensions/emoji/js/dist/forum.js.map
generated
vendored
2
extensions/emoji/js/dist/forum.js.map
generated
vendored
File diff suppressed because one or more lines are too long
@@ -70,6 +70,7 @@ export default function addComposerAutocomplete() {
|
||||
return (
|
||||
<Tooltip text={name}>
|
||||
<button
|
||||
type="button"
|
||||
key={emoji}
|
||||
onclick={() => applySuggestion(emoji)}
|
||||
onmouseenter={function () {
|
||||
|
@@ -19,7 +19,7 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"flarum/core": "^2.0.0-beta.2"
|
||||
"flarum/core": "^2.0.0-beta.3"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
|
@@ -7,7 +7,7 @@
|
||||
],
|
||||
"license": "MIT",
|
||||
"require": {
|
||||
"flarum/core": "^2.0.0-beta.2"
|
||||
"flarum/core": "^2.0.0-beta.3"
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@@ -19,7 +19,7 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"flarum/core": "^2.0.0-beta.2"
|
||||
"flarum/core": "^2.0.0-beta.3"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
|
@@ -19,7 +19,7 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"flarum/core": "^2.0.0-beta.2"
|
||||
"flarum/core": "^2.0.0-beta.3"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
|
2
extensions/lock/js/dist/forum.js
generated
vendored
2
extensions/lock/js/dist/forum.js
generated
vendored
@@ -1,2 +1,2 @@
|
||||
(()=>{var o={n:e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return o.d(t,{a:t}),t},d:(e,t)=>{for(var n in t)o.o(t,n)&&!o.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},o:(o,e)=>Object.prototype.hasOwnProperty.call(o,e),r:o=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(o,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(o,"__esModule",{value:!0})}},e={};(()=>{"use strict";o.r(e),o.d(e,{extend:()=>N});const t=flarum.reg.get("core","common/extend"),n=flarum.reg.get("core","forum/app");var r=o.n(n);const s=flarum.reg.get("core","common/models/Discussion");var c=o.n(s);const a=flarum.reg.get("core","common/components/Badge");var i=o.n(a);const l=flarum.reg.get("core","forum/utils/DiscussionControls");var u=o.n(l);const d=flarum.reg.get("core","forum/components/DiscussionPage");var f=o.n(d);const k=flarum.reg.get("core","common/components/Button");var g=o.n(k);const p=flarum.reg.get("core","common/extenders");var b=o.n(p);const y=flarum.reg.get("core","forum/components/EventPost");var _=o.n(y);class v extends(_()){icon(){return this.attrs.post.content().locked?"fas fa-lock":"fas fa-unlock"}descriptionKey(){return this.attrs.post.content().locked?"flarum-lock.forum.post_stream.discussion_locked_text":"flarum-lock.forum.post_stream.discussion_unlocked_text"}}flarum.reg.add("flarum-lock","forum/components/DiscussionLockedPost",v);const x=flarum.reg.get("core","common/query/IGambit"),L=flarum.reg.get("core","common/app");var h=o.n(L);class P extends x.BooleanGambit{key(){return h().translator.trans("flarum-lock.lib.gambits.discussions.locked.key",{},!0)}filterKey(){return"locked"}}flarum.reg.add("flarum-lock","common/query/discussions/LockedGambit",P);const w=[(new(b().Search)).gambit("discussions",P)],S=flarum.reg.get("core","forum/components/Notification");var j=o.n(S);class D extends(j()){icon(){return"fas fa-lock"}href(){const o=this.attrs.notification;return r().route.discussion(o.subject(),o.content().postNumber)}content(){return r().translator.trans("flarum-lock.forum.notifications.discussion_locked_text",{user:this.attrs.notification.fromUser()})}excerpt(){return null}}flarum.reg.add("flarum-lock","forum/components/DiscussionLockedNotification",D);const N=[...w,(new(b().PostTypes)).add("discussionLocked",v),(new(b().Notification)).add("discussionLocked",D),new(b().Model)(c()).attribute("isLocked").attribute("canLock")];r().initializers.add("flarum-lock",(()=>{(0,t.extend)(c().prototype,"badges",(function(o){this.isLocked()&&o.add("locked",m(i(),{type:"locked",label:r().translator.trans("flarum-lock.forum.badge.locked_tooltip"),icon:"fas fa-lock"}))})),(0,t.extend)(u(),"moderationControls",(function(o,e){e.canLock()&&o.add("lock",m(g(),{icon:"fas fa-lock",onclick:this.lockAction.bind(e)},r().translator.trans(`flarum-lock.forum.discussion_controls.${e.isLocked()?"unlock":"lock"}_button`)))})),u().lockAction=function(){this.save({isLocked:!this.isLocked()}).then((()=>{r().current.matches(f())&&r().current.get("stream").update(),m.redraw()}))},(0,t.extend)("flarum/forum/components/NotificationGrid","notificationTypes",(function(o){o.add("discussionLocked",{name:"discussionLocked",icon:"fas fa-lock",label:r().translator.trans("flarum-lock.forum.settings.notify_discussion_locked_label")})}))}))})(),module.exports=e})();
|
||||
(()=>{var o={n:e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return o.d(t,{a:t}),t},d:(e,t)=>{for(var n in t)o.o(t,n)&&!o.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},o:(o,e)=>Object.prototype.hasOwnProperty.call(o,e),r:o=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(o,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(o,"__esModule",{value:!0})}},e={};(()=>{"use strict";o.r(e),o.d(e,{extend:()=>N});const t=flarum.reg.get("core","common/extend"),n=flarum.reg.get("core","forum/app");var r=o.n(n);const s=flarum.reg.get("core","common/models/Discussion");var c=o.n(s);const a=flarum.reg.get("core","common/components/Badge");var i=o.n(a);const l=flarum.reg.get("core","forum/utils/DiscussionControls");var u=o.n(l);const d=flarum.reg.get("core","forum/components/DiscussionPage");var f=o.n(d);const k=flarum.reg.get("core","common/components/Button");var g=o.n(k);const p=flarum.reg.get("core","common/extenders");var b=o.n(p);const y=flarum.reg.get("core","forum/components/EventPost");var _=o.n(y);class v extends(_()){icon(){return this.attrs.post.content().locked?"fas fa-lock":"fas fa-unlock"}descriptionKey(){return this.attrs.post.content().locked?"flarum-lock.forum.post_stream.discussion_locked_text":"flarum-lock.forum.post_stream.discussion_unlocked_text"}}flarum.reg.add("flarum-lock","forum/components/DiscussionLockedPost",v);const x=flarum.reg.get("core","common/query/IGambit"),L=flarum.reg.get("core","common/app");var h=o.n(L);class P extends x.BooleanGambit{key(){return h().translator.trans("flarum-lock.lib.gambits.discussions.locked.key",{},!0)}filterKey(){return"locked"}}flarum.reg.add("flarum-lock","common/query/discussions/LockedGambit",P);const w=[(new(b().Search)).gambit("discussions",P)],S=flarum.reg.get("core","forum/components/Notification");var j=o.n(S);class D extends(j()){icon(){return"fas fa-lock"}href(){const o=this.attrs.notification;return r().route.discussion(o.subject(),o.content().postNumber)}content(){return r().translator.trans("flarum-lock.forum.notifications.discussion_locked_text",{user:this.attrs.notification.fromUser()})}excerpt(){return null}}flarum.reg.add("flarum-lock","forum/components/DiscussionLockedNotification",D);const N=[...w,(new(b().PostTypes)).add("discussionLocked",v),(new(b().Notification)).add("discussionLocked",D),new(b().Model)(c()).attribute("isLocked").attribute("canLock")];r().initializers.add("flarum-lock",(()=>{(0,t.extend)(c().prototype,"badges",(function(o){this.isLocked()&&o.add("locked",m(i(),{type:"locked",label:r().translator.trans("flarum-lock.forum.badge.locked_tooltip"),icon:"fas fa-lock",tabindex:"0"}))})),(0,t.extend)(u(),"moderationControls",(function(o,e){e.canLock()&&o.add("lock",m(g(),{icon:"fas fa-lock",onclick:this.lockAction.bind(e)},r().translator.trans(`flarum-lock.forum.discussion_controls.${e.isLocked()?"unlock":"lock"}_button`)))})),u().lockAction=function(){this.save({isLocked:!this.isLocked()}).then((()=>{r().current.matches(f())&&r().current.get("stream").update(),m.redraw()}))},(0,t.extend)("flarum/forum/components/NotificationGrid","notificationTypes",(function(o){o.add("discussionLocked",{name:"discussionLocked",icon:"fas fa-lock",label:r().translator.trans("flarum-lock.forum.settings.notify_discussion_locked_label")})}))}))})(),module.exports=e})();
|
||||
//# sourceMappingURL=forum.js.map
|
2
extensions/lock/js/dist/forum.js.map
generated
vendored
2
extensions/lock/js/dist/forum.js.map
generated
vendored
File diff suppressed because one or more lines are too long
@@ -6,7 +6,10 @@ import Badge from 'flarum/common/components/Badge';
|
||||
export default function addLockBadge() {
|
||||
extend(Discussion.prototype, 'badges', function (badges) {
|
||||
if (this.isLocked()) {
|
||||
badges.add('locked', <Badge type="locked" label={app.translator.trans('flarum-lock.forum.badge.locked_tooltip')} icon="fas fa-lock" />);
|
||||
badges.add(
|
||||
'locked',
|
||||
<Badge type="locked" label={app.translator.trans('flarum-lock.forum.badge.locked_tooltip')} icon="fas fa-lock" tabindex="0" />
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@@ -19,7 +19,7 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"flarum/core": "^2.0.0-beta.2"
|
||||
"flarum/core": "^2.0.0-beta.3"
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@@ -19,7 +19,7 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"flarum/core": "^2.0.0-beta.2"
|
||||
"flarum/core": "^2.0.0-beta.3"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
|
2
extensions/mentions/js/dist/forum.js
generated
vendored
2
extensions/mentions/js/dist/forum.js
generated
vendored
File diff suppressed because one or more lines are too long
2
extensions/mentions/js/dist/forum.js.map
generated
vendored
2
extensions/mentions/js/dist/forum.js.map
generated
vendored
File diff suppressed because one or more lines are too long
@@ -17,7 +17,7 @@ export default class MentionsDropdownItem<CustomAttrs extends IMentionsDropdownI
|
||||
const className = classList('MentionsDropdownItem', 'PostPreview', `MentionsDropdown-${mentionable.type()}`);
|
||||
|
||||
return (
|
||||
<button className={className} {...attrs}>
|
||||
<button className={className} type="button" {...attrs}>
|
||||
<span className="PostPreview-content">{vnode.children}</span>
|
||||
</button>
|
||||
);
|
||||
|
@@ -15,6 +15,7 @@ export default class PostQuoteButton extends Fragment {
|
||||
return (
|
||||
<button
|
||||
className="Button PostQuoteButton"
|
||||
type="button"
|
||||
onclick={() => {
|
||||
reply(this.post, this.content);
|
||||
}}
|
||||
|
@@ -7,7 +7,7 @@
|
||||
"type": "flarum-extension",
|
||||
"license": "MIT",
|
||||
"require": {
|
||||
"flarum/core": "^2.0.0-beta.2"
|
||||
"flarum/core": "^2.0.0-beta.3"
|
||||
},
|
||||
"authors": [
|
||||
{
|
||||
|
@@ -19,7 +19,7 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"flarum/core": "^2.0.0-beta.2"
|
||||
"flarum/core": "^2.0.0-beta.3"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
|
@@ -22,7 +22,7 @@
|
||||
"source": "https://github.com/flarum/extension-manager"
|
||||
},
|
||||
"require": {
|
||||
"flarum/core": "^2.0.0-beta.2",
|
||||
"flarum/core": "^2.0.0-beta.3",
|
||||
"composer/composer": "^2.7"
|
||||
},
|
||||
"require-dev": {
|
||||
|
@@ -32,7 +32,7 @@ use Tobyz\JsonApiServer\Schema\CustomFilter;
|
||||
|
||||
class ExternalExtensionResource extends AbstractResource implements Listable, Paginatable, Countable
|
||||
{
|
||||
protected int|null $totalResults = null;
|
||||
protected ?int $totalResults = null;
|
||||
|
||||
public function __construct(
|
||||
protected Repository $cache,
|
||||
|
@@ -20,6 +20,11 @@ use Throwable;
|
||||
|
||||
class ComposerCommandJob extends AbstractJob implements ShouldBeUnique
|
||||
{
|
||||
/**
|
||||
* The number of seconds the job can run before timing out.
|
||||
*/
|
||||
public int $timeout = 60 * 3;
|
||||
|
||||
public function __construct(
|
||||
protected AbstractActionCommand $command,
|
||||
protected string $phpVersion
|
||||
|
@@ -19,7 +19,7 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"flarum/core": "^2.0.0-beta.2",
|
||||
"flarum/core": "^2.0.0-beta.3",
|
||||
"pusher/pusher-php-server": "^7.2"
|
||||
},
|
||||
"require-dev": {
|
||||
|
@@ -19,7 +19,7 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"flarum/core": "^2.0.0-beta.2"
|
||||
"flarum/core": "^2.0.0-beta.3"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
|
2
extensions/statistics/js/dist/admin.js
generated
vendored
2
extensions/statistics/js/dist/admin.js
generated
vendored
File diff suppressed because one or more lines are too long
2
extensions/statistics/js/dist/admin.js.map
generated
vendored
2
extensions/statistics/js/dist/admin.js.map
generated
vendored
File diff suppressed because one or more lines are too long
@@ -279,6 +279,7 @@ export default class StatisticsWidget extends DashboardWidget {
|
||||
return (
|
||||
<button
|
||||
className={classList('Button--ua-reset StatisticsWidget-entity', { active: this.selectedEntity === entity })}
|
||||
type="button"
|
||||
onclick={this.changeEntity.bind(this, entity)}
|
||||
>
|
||||
<h3 className="StatisticsWidget-heading">{app.translator.trans('flarum-statistics.admin.statistics.' + entity + '_heading')}</h3>
|
||||
|
@@ -19,7 +19,7 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"flarum/core": "^2.0.0-beta.2"
|
||||
"flarum/core": "^2.0.0-beta.3"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
|
2
extensions/sticky/js/dist/forum.js
generated
vendored
2
extensions/sticky/js/dist/forum.js
generated
vendored
@@ -1,2 +1,2 @@
|
||||
(()=>{var t={n:e=>{var s=e&&e.__esModule?()=>e.default:()=>e;return t.d(s,{a:s}),s},d:(e,s)=>{for(var r in s)t.o(s,r)&&!t.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:s[r]})},o:(t,e)=>Object.prototype.hasOwnProperty.call(t,e),r:t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})}},e={};(()=>{"use strict";t.r(e),t.d(e,{extend:()=>B});const s=flarum.reg.get("core","forum/app");var r=t.n(s);const o=flarum.reg.get("core","common/extend"),n=flarum.reg.get("core","common/models/Discussion");var c=t.n(n);const i=flarum.reg.get("core","common/components/Badge");var a=t.n(i);const u=flarum.reg.get("core","forum/utils/DiscussionControls");var l=t.n(u);const d=flarum.reg.get("core","forum/components/DiscussionPage");var f=t.n(d);const y=flarum.reg.get("core","common/components/Button");var g=t.n(y);const p=flarum.reg.get("core","forum/states/DiscussionListState");var k=t.n(p);const b=flarum.reg.get("core","forum/components/DiscussionListItem");var v=t.n(b);const S=flarum.reg.get("core","forum/components/IndexPage");var h=t.n(S);const x=flarum.reg.get("core","common/utils/string"),P=flarum.reg.get("core","common/utils/classList");var _=t.n(P);const D=flarum.reg.get("core","common/extenders");var w=t.n(D);const I=flarum.reg.get("core","forum/components/EventPost");var O=t.n(I);class j extends(O()){icon(){return"fas fa-thumbtack"}descriptionKey(){return this.attrs.post.content().sticky?"flarum-sticky.forum.post_stream.discussion_stickied_text":"flarum-sticky.forum.post_stream.discussion_unstickied_text"}}flarum.reg.add("flarum-sticky","forum/components/DiscussionStickiedPost",j);const q=flarum.reg.get("core","common/query/IGambit"),L=flarum.reg.get("core","common/app");var M=t.n(L);class A extends q.BooleanGambit{key(){return M().translator.trans("flarum-sticky.lib.gambits.discussions.sticky.key",{},!0)}filterKey(){return"sticky"}}flarum.reg.add("flarum-sticky","common/query/discussions/StickyGambit",A);const B=[(new(w().Search)).gambit("discussions",A),(new(w().PostTypes)).add("discussionStickied",j),new(w().Model)(c()).attribute("isSticky").attribute("canSticky")];r().initializers.add("flarum-sticky",(()=>{(0,o.extend)(c().prototype,"badges",(function(t){this.isSticky()&&t.add("sticky",m(a(),{type:"sticky",label:r().translator.trans("flarum-sticky.forum.badge.sticky_tooltip"),icon:"fas fa-thumbtack"}),10)})),(0,o.extend)(l(),"moderationControls",(function(t,e){e.canSticky()&&t.add("sticky",m(g(),{icon:"fas fa-thumbtack",onclick:this.stickyAction.bind(e)},r().translator.trans(`flarum-sticky.forum.discussion_controls.${e.isSticky()?"unsticky":"sticky"}_button`)))})),l().stickyAction=function(){this.save({isSticky:!this.isSticky()}).then((()=>{r().current.matches(f())&&r().current.get("stream").update(),m.redraw()}))},(0,o.extend)(k().prototype,"requestParams",(function(t){r().forum.attribute("excerptDisplayEnabled")&&(r().current.matches(h())||r().current.matches(f()))&&t.include.push("firstPost")})),(0,o.extend)(v().prototype,"infoItems",(function(t){const e=this.attrs.discussion;if(r().forum.attribute("excerptDisplayEnabled")&&e.isSticky()&&!this.attrs.params.q&&!e.lastReadPostNumber()){const s=e.firstPost();if(s){const e=(0,x.truncate)(s.contentPlain(),175);t.add("excerpt",m("div",null,e),-100)}}})),(0,o.extend)(v().prototype,"elementAttrs",(function(t){this.attrs.discussion.isSticky()&&(t.className=_()(t.className,"DiscussionListItem--sticky"))}))}))})(),module.exports=e})();
|
||||
(()=>{var t={n:e=>{var s=e&&e.__esModule?()=>e.default:()=>e;return t.d(s,{a:s}),s},d:(e,s)=>{for(var r in s)t.o(s,r)&&!t.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:s[r]})},o:(t,e)=>Object.prototype.hasOwnProperty.call(t,e),r:t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})}},e={};(()=>{"use strict";t.r(e),t.d(e,{extend:()=>B});const s=flarum.reg.get("core","forum/app");var r=t.n(s);const o=flarum.reg.get("core","common/extend"),n=flarum.reg.get("core","common/models/Discussion");var c=t.n(n);const i=flarum.reg.get("core","common/components/Badge");var a=t.n(i);const u=flarum.reg.get("core","forum/utils/DiscussionControls");var l=t.n(u);const d=flarum.reg.get("core","forum/components/DiscussionPage");var f=t.n(d);const y=flarum.reg.get("core","common/components/Button");var g=t.n(y);const p=flarum.reg.get("core","forum/states/DiscussionListState");var k=t.n(p);const b=flarum.reg.get("core","forum/components/DiscussionListItem");var v=t.n(b);const S=flarum.reg.get("core","forum/components/IndexPage");var h=t.n(S);const x=flarum.reg.get("core","common/utils/string"),P=flarum.reg.get("core","common/utils/classList");var _=t.n(P);const D=flarum.reg.get("core","common/extenders");var w=t.n(D);const I=flarum.reg.get("core","forum/components/EventPost");var O=t.n(I);class j extends(O()){icon(){return"fas fa-thumbtack"}descriptionKey(){return this.attrs.post.content().sticky?"flarum-sticky.forum.post_stream.discussion_stickied_text":"flarum-sticky.forum.post_stream.discussion_unstickied_text"}}flarum.reg.add("flarum-sticky","forum/components/DiscussionStickiedPost",j);const q=flarum.reg.get("core","common/query/IGambit"),L=flarum.reg.get("core","common/app");var M=t.n(L);class A extends q.BooleanGambit{key(){return M().translator.trans("flarum-sticky.lib.gambits.discussions.sticky.key",{},!0)}filterKey(){return"sticky"}}flarum.reg.add("flarum-sticky","common/query/discussions/StickyGambit",A);const B=[(new(w().Search)).gambit("discussions",A),(new(w().PostTypes)).add("discussionStickied",j),new(w().Model)(c()).attribute("isSticky").attribute("canSticky")];r().initializers.add("flarum-sticky",(()=>{(0,o.extend)(c().prototype,"badges",(function(t){this.isSticky()&&t.add("sticky",m(a(),{type:"sticky",label:r().translator.trans("flarum-sticky.forum.badge.sticky_tooltip"),icon:"fas fa-thumbtack",tabindex:"0"}),10)})),(0,o.extend)(l(),"moderationControls",(function(t,e){e.canSticky()&&t.add("sticky",m(g(),{icon:"fas fa-thumbtack",onclick:this.stickyAction.bind(e)},r().translator.trans(`flarum-sticky.forum.discussion_controls.${e.isSticky()?"unsticky":"sticky"}_button`)))})),l().stickyAction=function(){this.save({isSticky:!this.isSticky()}).then((()=>{r().current.matches(f())&&r().current.get("stream").update(),m.redraw()}))},(0,o.extend)(k().prototype,"requestParams",(function(t){r().forum.attribute("excerptDisplayEnabled")&&(r().current.matches(h())||r().current.matches(f()))&&t.include.push("firstPost")})),(0,o.extend)(v().prototype,"infoItems",(function(t){const e=this.attrs.discussion;if(r().forum.attribute("excerptDisplayEnabled")&&e.isSticky()&&!this.attrs.params.q&&!e.lastReadPostNumber()){const s=e.firstPost();if(s){const e=(0,x.truncate)(s.contentPlain(),175);t.add("excerpt",m("div",null,e),-100)}}})),(0,o.extend)(v().prototype,"elementAttrs",(function(t){this.attrs.discussion.isSticky()&&(t.className=_()(t.className,"DiscussionListItem--sticky"))}))}))})(),module.exports=e})();
|
||||
//# sourceMappingURL=forum.js.map
|
2
extensions/sticky/js/dist/forum.js.map
generated
vendored
2
extensions/sticky/js/dist/forum.js.map
generated
vendored
File diff suppressed because one or more lines are too long
@@ -8,7 +8,7 @@ export default function addStickyBadge() {
|
||||
if (this.isSticky()) {
|
||||
badges.add(
|
||||
'sticky',
|
||||
<Badge type="sticky" label={app.translator.trans('flarum-sticky.forum.badge.sticky_tooltip')} icon="fas fa-thumbtack" />,
|
||||
<Badge type="sticky" label={app.translator.trans('flarum-sticky.forum.badge.sticky_tooltip')} icon="fas fa-thumbtack" tabindex="0" />,
|
||||
10
|
||||
);
|
||||
}
|
||||
|
@@ -19,7 +19,7 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"flarum/core": "^2.0.0-beta.2"
|
||||
"flarum/core": "^2.0.0-beta.3"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
|
2
extensions/subscriptions/js/dist/forum.js
generated
vendored
2
extensions/subscriptions/js/dist/forum.js
generated
vendored
File diff suppressed because one or more lines are too long
2
extensions/subscriptions/js/dist/forum.js.map
generated
vendored
2
extensions/subscriptions/js/dist/forum.js.map
generated
vendored
File diff suppressed because one or more lines are too long
@@ -9,11 +9,25 @@ export default function addSubscriptionBadge() {
|
||||
|
||||
switch (this.subscription()) {
|
||||
case 'follow':
|
||||
badge = <Badge label={app.translator.trans('flarum-subscriptions.forum.badge.following_tooltip')} icon="fas fa-star" type="following" />;
|
||||
badge = (
|
||||
<Badge
|
||||
label={app.translator.trans('flarum-subscriptions.forum.badge.following_tooltip')}
|
||||
icon="fas fa-star"
|
||||
type="following"
|
||||
tabindex="0"
|
||||
/>
|
||||
);
|
||||
break;
|
||||
|
||||
case 'ignore':
|
||||
badge = <Badge label={app.translator.trans('flarum-subscriptions.forum.badge.ignoring_tooltip')} icon="far fa-eye-slash" type="ignoring" />;
|
||||
badge = (
|
||||
<Badge
|
||||
label={app.translator.trans('flarum-subscriptions.forum.badge.ignoring_tooltip')}
|
||||
icon="far fa-eye-slash"
|
||||
type="ignoring"
|
||||
tabindex="0"
|
||||
/>
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@@ -19,7 +19,7 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"flarum/core": "^2.0.0-beta.2"
|
||||
"flarum/core": "^2.0.0-beta.3"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
|
2
extensions/suspend/js/dist/forum.js
generated
vendored
2
extensions/suspend/js/dist/forum.js
generated
vendored
File diff suppressed because one or more lines are too long
2
extensions/suspend/js/dist/forum.js.map
generated
vendored
2
extensions/suspend/js/dist/forum.js.map
generated
vendored
File diff suppressed because one or more lines are too long
@@ -28,7 +28,7 @@ app.initializers.add('flarum-suspend', () => {
|
||||
if (new Date() < until) {
|
||||
items.add(
|
||||
'suspended',
|
||||
<Badge icon="fas fa-ban" type="suspended" label={app.translator.trans('flarum-suspend.forum.user_badge.suspended_tooltip')} />,
|
||||
<Badge icon="fas fa-ban" type="suspended" label={app.translator.trans('flarum-suspend.forum.user_badge.suspended_tooltip')} tabindex="0" />,
|
||||
100
|
||||
);
|
||||
}
|
||||
|
@@ -19,7 +19,7 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"flarum/core": "^2.0.0-beta.2"
|
||||
"flarum/core": "^2.0.0-beta.3"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
|
@@ -41,7 +41,7 @@ class Tag
|
||||
$slug = Arr::pull($queryParams, 'slug');
|
||||
$sort = Arr::pull($queryParams, 'sort');
|
||||
$q = Arr::pull($queryParams, 'q', '');
|
||||
$page = Arr::pull($queryParams, 'page', 1);
|
||||
$page = max(1, intval(Arr::pull($queryParams, 'page')));
|
||||
$filters = Arr::pull($queryParams, 'filter', []);
|
||||
|
||||
$sortMap = $this->resource->sortMap();
|
||||
|
2
framework/core/js/dist-typings/admin/AdminApplication.d.ts
generated
vendored
2
framework/core/js/dist-typings/admin/AdminApplication.d.ts
generated
vendored
@@ -87,7 +87,7 @@ export default class AdminApplication extends Application {
|
||||
data: AdminApplicationData;
|
||||
route: typeof Application.prototype.route & AdminRoutes;
|
||||
constructor();
|
||||
protected beforeMount(): void;
|
||||
protected runBeforeMount(): void;
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
|
6
framework/core/js/dist-typings/admin/components/AppearancePage.d.ts
generated
vendored
6
framework/core/js/dist-typings/admin/components/AppearancePage.d.ts
generated
vendored
@@ -8,7 +8,11 @@ export default class AppearancePage extends AdminPage {
|
||||
title: string | any[];
|
||||
description: string | any[];
|
||||
};
|
||||
content(): JSX.Element;
|
||||
content(): (Mithril.Children & {
|
||||
itemName: string;
|
||||
})[];
|
||||
contentItems(): ItemList<Mithril.Children>;
|
||||
brandingItems(): ItemList<Mithril.Children>;
|
||||
colorItems(): ItemList<Mithril.Children>;
|
||||
onsaved(): void;
|
||||
static register(): void;
|
||||
|
26
framework/core/js/dist-typings/admin/utils/AdminRegistry.d.ts
generated
vendored
26
framework/core/js/dist-typings/admin/utils/AdminRegistry.d.ts
generated
vendored
@@ -54,7 +54,19 @@ export default class AdminRegistry {
|
||||
* label: app.translator.trans('flarum-flags.admin.settings.guidelines_url_label')
|
||||
* }, 15) // priority is optional (ItemList)
|
||||
*/
|
||||
registerSetting(content: SettingConfigInput, priority?: number): this;
|
||||
registerSetting(content: SettingConfigInput, priority?: number, key?: string | null): this;
|
||||
/**
|
||||
* This function allows you to change the configuration of a setting.
|
||||
*/
|
||||
setSetting(key: string, content: SettingConfigInput | ((original: SettingConfigInput) => SettingConfigInput)): this;
|
||||
/**
|
||||
* This function allows you to change the priority of a setting.
|
||||
*/
|
||||
setSettingPriority(key: string, priority: number): this;
|
||||
/**
|
||||
* This function allows you to remove a setting.
|
||||
*/
|
||||
removeSetting(key: string): this;
|
||||
/**
|
||||
* This function registers your permission with Flarum
|
||||
*
|
||||
@@ -67,6 +79,18 @@ export default class AdminRegistry {
|
||||
* }, 'moderate', 65)
|
||||
*/
|
||||
registerPermission(content: PermissionConfig, permissionType: PermissionType, priority?: number): this;
|
||||
/**
|
||||
* This function allows you to change the configuration of a permission.
|
||||
*/
|
||||
setPermission(key: string, content: PermissionConfig | ((original: PermissionConfig) => PermissionConfig), permissionType: PermissionType): this;
|
||||
/**
|
||||
* This function allows you to change the priority of a permission.
|
||||
*/
|
||||
setPermissionPriority(key: string, permissionType: PermissionType, priority: number): this;
|
||||
/**
|
||||
* This function allows you to remove a permission.
|
||||
*/
|
||||
removePermission(key: string, permissionType: PermissionType): this;
|
||||
/**
|
||||
* Replace the default extension page with a custom component.
|
||||
* This component would typically extend ExtensionPage
|
||||
|
4
framework/core/js/dist-typings/common/Application.d.ts
generated
vendored
4
framework/core/js/dist-typings/common/Application.d.ts
generated
vendored
@@ -210,10 +210,12 @@ export default class Application {
|
||||
*/
|
||||
currentInitializerExtension: string | null;
|
||||
private handledErrors;
|
||||
private beforeMounts;
|
||||
load(payload: Application['data']): void;
|
||||
protected initialize(): CallableFunction[];
|
||||
boot(): void;
|
||||
protected beforeMount(): void;
|
||||
beforeMount(callback: () => void): void;
|
||||
protected runBeforeMount(): void;
|
||||
bootExtensions(extensions: Record<string, {
|
||||
extend?: IExtender[];
|
||||
}>): void;
|
||||
|
55
framework/core/js/dist-typings/common/extenders/Admin.d.ts
generated
vendored
55
framework/core/js/dist-typings/common/extenders/Admin.d.ts
generated
vendored
@@ -1,29 +1,66 @@
|
||||
import IExtender, { IExtensionModule } from './IExtender';
|
||||
import type AdminApplication from '../../admin/AdminApplication';
|
||||
import type { CustomExtensionPage, SettingConfigInternal } from '../../admin/utils/AdminRegistry';
|
||||
import type { CustomExtensionPage, SettingConfigInput } from '../../admin/utils/AdminRegistry';
|
||||
import type { PermissionConfig, PermissionType } from '../../admin/components/PermissionGrid';
|
||||
import type Mithril from 'mithril';
|
||||
import type { GeneralIndexItem } from '../../admin/states/GeneralSearchIndex';
|
||||
export default class Admin implements IExtender<AdminApplication> {
|
||||
protected context: string | null;
|
||||
protected settings: {
|
||||
setting?: () => SettingConfigInternal | null;
|
||||
setting?: () => SettingConfigInput | null;
|
||||
customSetting?: () => Mithril.Children;
|
||||
priority: number;
|
||||
}[];
|
||||
protected settingReplacements: {
|
||||
setting: string;
|
||||
replacement: (original: SettingConfigInput) => SettingConfigInput;
|
||||
}[];
|
||||
protected settingPriorityChanges: {
|
||||
setting: string;
|
||||
priority: number;
|
||||
}[];
|
||||
protected settingRemovals: string[];
|
||||
protected permissions: {
|
||||
permission: () => PermissionConfig | null;
|
||||
type: PermissionType;
|
||||
priority: number;
|
||||
}[];
|
||||
protected permissionsReplacements: {
|
||||
permission: string;
|
||||
type: PermissionType;
|
||||
replacement: (original: PermissionConfig) => PermissionConfig;
|
||||
}[];
|
||||
protected permissionsPriorityChanges: {
|
||||
permission: string;
|
||||
type: PermissionType;
|
||||
priority: number;
|
||||
}[];
|
||||
protected permissionsRemovals: {
|
||||
permission: string;
|
||||
type: PermissionType;
|
||||
}[];
|
||||
protected customPage: CustomExtensionPage | null;
|
||||
protected generalIndexes: {
|
||||
settings?: () => GeneralIndexItem[];
|
||||
permissions?: () => GeneralIndexItem[];
|
||||
};
|
||||
constructor(context?: string | null);
|
||||
/**
|
||||
* Register a setting to be shown on the extension's settings page.
|
||||
*/
|
||||
setting(setting: () => SettingConfigInternal | null, priority?: number): this;
|
||||
setting(setting: () => SettingConfigInput | null, priority?: number): this;
|
||||
/**
|
||||
* Replace an existing setting's configuration.
|
||||
*/
|
||||
replaceSetting(setting: string, replacement: (original: SettingConfigInput) => SettingConfigInput): this;
|
||||
/**
|
||||
* Change the priority of an existing setting.
|
||||
*/
|
||||
setSettingPriority(setting: string, priority: number): this;
|
||||
/**
|
||||
* Remove a setting from the extension's settings page.
|
||||
*/
|
||||
removeSetting(setting: string): this;
|
||||
/**
|
||||
* Register a custom setting to be shown on the extension's settings page.
|
||||
*/
|
||||
@@ -32,6 +69,18 @@ export default class Admin implements IExtender<AdminApplication> {
|
||||
* Register a permission to be shown on the extension's permissions page.
|
||||
*/
|
||||
permission(permission: () => PermissionConfig | null, type: PermissionType, priority?: number): this;
|
||||
/**
|
||||
* Replace an existing permission's configuration.
|
||||
*/
|
||||
replacePermission(permission: string, replacement: (original: PermissionConfig) => PermissionConfig, type: PermissionType): this;
|
||||
/**
|
||||
* Change the priority of an existing permission.
|
||||
*/
|
||||
setPermissionPriority(permission: string, type: PermissionType, priority: number): this;
|
||||
/**
|
||||
* Remove a permission from the extension's permissions page.
|
||||
*/
|
||||
removePermission(permission: string, type: PermissionType): this;
|
||||
/**
|
||||
* Register a custom page to be shown in the admin interface.
|
||||
*/
|
||||
|
5
framework/core/js/dist-typings/common/utils/a11y.d.ts
generated
vendored
Normal file
5
framework/core/js/dist-typings/common/utils/a11y.d.ts
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
/**
|
||||
* Fix a11y skip links by manually focusing on the href target element.
|
||||
* This prevents unwanted/unexpected reloads of the page.
|
||||
*/
|
||||
export declare function prepareSkipLinks(): void;
|
2
framework/core/js/dist/admin.js
generated
vendored
2
framework/core/js/dist/admin.js
generated
vendored
File diff suppressed because one or more lines are too long
2
framework/core/js/dist/admin.js.map
generated
vendored
2
framework/core/js/dist/admin.js.map
generated
vendored
File diff suppressed because one or more lines are too long
2
framework/core/js/dist/forum.js
generated
vendored
2
framework/core/js/dist/forum.js
generated
vendored
File diff suppressed because one or more lines are too long
2
framework/core/js/dist/forum.js.map
generated
vendored
2
framework/core/js/dist/forum.js.map
generated
vendored
File diff suppressed because one or more lines are too long
2
framework/core/js/dist/forum/components/PostStream.js
generated
vendored
2
framework/core/js/dist/forum/components/PostStream.js
generated
vendored
File diff suppressed because one or more lines are too long
2
framework/core/js/dist/forum/components/PostStream.js.map
generated
vendored
2
framework/core/js/dist/forum/components/PostStream.js.map
generated
vendored
File diff suppressed because one or more lines are too long
2
framework/core/js/dist/forum/components/PostStreamScrubber.js
generated
vendored
2
framework/core/js/dist/forum/components/PostStreamScrubber.js
generated
vendored
File diff suppressed because one or more lines are too long
2
framework/core/js/dist/forum/components/PostStreamScrubber.js.map
generated
vendored
2
framework/core/js/dist/forum/components/PostStreamScrubber.js.map
generated
vendored
File diff suppressed because one or more lines are too long
@@ -129,12 +129,14 @@ export default class AdminApplication extends Application {
|
||||
this.route = (Object.getPrototypeOf(Object.getPrototypeOf(this)) as Application).route.bind(this);
|
||||
}
|
||||
|
||||
protected beforeMount(): void {
|
||||
protected runBeforeMount(): void {
|
||||
BasicsPage.register();
|
||||
AppearancePage.register();
|
||||
MailPage.register();
|
||||
AdvancedPage.register();
|
||||
PermissionsPage.register();
|
||||
|
||||
super.runBeforeMount();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -67,7 +67,13 @@ export default abstract class AdminPage<CustomAttrs extends IPageAttrs = IPageAt
|
||||
*/
|
||||
submitButton(): Mithril.Children {
|
||||
return (
|
||||
<Button onclick={this.saveSettings.bind(this)} className="Button Button--primary" loading={this.loading} disabled={!this.isChanged()}>
|
||||
<Button
|
||||
type="submit"
|
||||
onclick={this.saveSettings.bind(this)}
|
||||
className="Button Button--primary"
|
||||
loading={this.loading}
|
||||
disabled={!this.isChanged()}
|
||||
>
|
||||
{app.translator.trans('core.admin.settings.submit_button')}
|
||||
</Button>
|
||||
);
|
||||
|
@@ -22,8 +22,14 @@ export default class AppearancePage extends AdminPage {
|
||||
}
|
||||
|
||||
content() {
|
||||
return (
|
||||
<>
|
||||
return this.contentItems().toArray();
|
||||
}
|
||||
|
||||
contentItems(): ItemList<Mithril.Children> {
|
||||
const items = new ItemList<Mithril.Children>();
|
||||
|
||||
items.add(
|
||||
'colors',
|
||||
<Form>
|
||||
<FieldSet
|
||||
className="AppearancePage-colors"
|
||||
@@ -32,47 +38,75 @@ export default class AppearancePage extends AdminPage {
|
||||
>
|
||||
{this.colorItems().toArray()}
|
||||
</FieldSet>
|
||||
</Form>
|
||||
</Form>,
|
||||
100
|
||||
);
|
||||
|
||||
<Form>
|
||||
items.add('branding', <Form>{this.brandingItems().toArray()}</Form>, 90);
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
brandingItems(): ItemList<Mithril.Children> {
|
||||
const items = new ItemList<Mithril.Children>();
|
||||
|
||||
items.add(
|
||||
'logo',
|
||||
<div className="Form-group">
|
||||
<label>{app.translator.trans('core.admin.appearance.logo_heading')}</label>
|
||||
<div className="helpText">{app.translator.trans('core.admin.appearance.logo_text')}</div>
|
||||
<UploadImageButton name="logo" routePath="logo" value={app.data.settings.logo_path} url={app.forum.attribute('logoUrl')} />
|
||||
</div>
|
||||
</div>,
|
||||
100
|
||||
);
|
||||
|
||||
items.add(
|
||||
'favicon',
|
||||
<div className="Form-group">
|
||||
<label>{app.translator.trans('core.admin.appearance.favicon_heading')}</label>
|
||||
<div className="helpText">{app.translator.trans('core.admin.appearance.favicon_text')}</div>
|
||||
<UploadImageButton name="favicon" routePath="favicon" value={app.data.settings.favicon_path} url={app.forum.attribute('faviconUrl')} />
|
||||
</div>
|
||||
</div>,
|
||||
90
|
||||
);
|
||||
|
||||
items.add(
|
||||
'custom-header',
|
||||
<div className="Form-group">
|
||||
<label>{app.translator.trans('core.admin.appearance.custom_header_heading')}</label>
|
||||
<div className="helpText">{app.translator.trans('core.admin.appearance.custom_header_text')}</div>
|
||||
<Button className="Button" onclick={() => app.modal.show(EditCustomHeaderModal)}>
|
||||
{app.translator.trans('core.admin.appearance.edit_header_button')}
|
||||
</Button>
|
||||
</div>
|
||||
</div>,
|
||||
80
|
||||
);
|
||||
|
||||
items.add(
|
||||
'custom-footer',
|
||||
<div className="Form-group">
|
||||
<label>{app.translator.trans('core.admin.appearance.custom_footer_heading')}</label>
|
||||
<div className="helpText">{app.translator.trans('core.admin.appearance.custom_footer_text')}</div>
|
||||
<Button className="Button" onclick={() => app.modal.show(EditCustomFooterModal)}>
|
||||
{app.translator.trans('core.admin.appearance.edit_footer_button')}
|
||||
</Button>
|
||||
</div>
|
||||
</div>,
|
||||
70
|
||||
);
|
||||
|
||||
items.add(
|
||||
'custom-css',
|
||||
<div className="Form-group">
|
||||
<label>{app.translator.trans('core.admin.appearance.custom_styles_heading')}</label>
|
||||
<div className="helpText">{app.translator.trans('core.admin.appearance.custom_styles_text')}</div>
|
||||
<Button className="Button" onclick={() => app.modal.show(EditCustomCssModal)}>
|
||||
{app.translator.trans('core.admin.appearance.edit_css_button')}
|
||||
</Button>
|
||||
</div>
|
||||
</Form>
|
||||
</>
|
||||
</div>,
|
||||
60
|
||||
);
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
colorItems() {
|
||||
|
@@ -9,7 +9,7 @@ import Icon from '../../common/components/Icon';
|
||||
import PermissionGrid from './PermissionGrid';
|
||||
import escapeRegExp from '../../common/utils/escapeRegExp';
|
||||
import { GeneralIndexData, GeneralIndexItem } from '../states/GeneralSearchIndex';
|
||||
import { ExtensionConfig, SettingConfigInternal } from '../utils/AdminRegistry';
|
||||
import { ExtensionConfig, SettingConfigInput } from '../utils/AdminRegistry';
|
||||
import ItemList from '../../common/utils/ItemList';
|
||||
|
||||
export class GeneralSearchResult {
|
||||
@@ -94,7 +94,7 @@ export default class GeneralSearchSource implements GlobalSearchSource {
|
||||
for (const extensionId in data) {
|
||||
// settings
|
||||
const settings = data[extensionId]!.settings;
|
||||
let normalizedSettings: GeneralIndexItem[] | SettingConfigInternal[] = [];
|
||||
let normalizedSettings: GeneralIndexItem[] | SettingConfigInput[] = [];
|
||||
|
||||
if (settings instanceof ItemList) {
|
||||
normalizedSettings = settings?.toArray();
|
||||
@@ -113,7 +113,7 @@ export default class GeneralSearchSource implements GlobalSearchSource {
|
||||
const group = app.generalIndex.getGroup(extensionId);
|
||||
|
||||
if (this.itemHasQuery(label, query) || this.itemHasQuery(help, query)) {
|
||||
const id = extensionId + '-' + ('setting' in setting ? setting : setting.id);
|
||||
const id = extensionId + '-' + ('setting' in setting ? setting : 'id' in setting ? setting.id : '');
|
||||
|
||||
results.push(
|
||||
new GeneralSearchResult(
|
||||
|
@@ -25,12 +25,12 @@ export default class PermissionsPage extends AdminPage {
|
||||
.all<Group>('groups')
|
||||
.filter((group) => [Group.GUEST_ID, Group.MEMBER_ID].indexOf(group.id()!) === -1)
|
||||
.map((group) => (
|
||||
<button className="Button Group" onclick={() => app.modal.show(EditGroupModal, { group })}>
|
||||
<button className="Button Group" type="button" onclick={() => app.modal.show(EditGroupModal, { group })}>
|
||||
<GroupBadge group={group} className="Group-icon" label={null} />
|
||||
<span className="Group-name">{group.namePlural()}</span>
|
||||
</button>
|
||||
))}
|
||||
<button className="Button Group Group--add" onclick={() => app.modal.show(EditGroupModal)}>
|
||||
<button className="Button Group Group--add" type="button" onclick={() => app.modal.show(EditGroupModal)}>
|
||||
<Icon name="fas fa-plus" className="Group-icon" />
|
||||
<span className="Group-name">{app.translator.trans('core.admin.permissions.new_group_button')}</span>
|
||||
</button>
|
||||
|
@@ -352,6 +352,7 @@ export default class UserListPage extends AdminPage {
|
||||
<button
|
||||
onclick={toggleEmailVisibility}
|
||||
className="Button Button--text UserList-emailIconBtn"
|
||||
type="button"
|
||||
title={app.translator.trans('core.admin.users.grid.columns.email.visibility_show')}
|
||||
>
|
||||
<Icon name="far fa-eye-slash fa-fw" className="icon" />
|
||||
|
@@ -71,7 +71,7 @@ export default class AdminRegistry {
|
||||
* label: app.translator.trans('flarum-flags.admin.settings.guidelines_url_label')
|
||||
* }, 15) // priority is optional (ItemList)
|
||||
*/
|
||||
registerSetting(content: SettingConfigInput, priority = 0): this {
|
||||
registerSetting(content: SettingConfigInput, priority = 0, key: string | null = null): this {
|
||||
if (this.state.currentExtension === null) {
|
||||
throw new Error(noActiveExtensionErrorMessage);
|
||||
}
|
||||
@@ -83,7 +83,7 @@ export default class AdminRegistry {
|
||||
// To support multiple such items for one extension, we assign a random ID.
|
||||
// 36 is arbitrary length, but makes collisions very unlikely.
|
||||
if (tmpContent instanceof Function) {
|
||||
tmpContent.setting = Math.random().toString(36);
|
||||
tmpContent.setting = key || Math.random().toString(36);
|
||||
}
|
||||
|
||||
const settings = this.state.data[this.state.currentExtension].settings || new ItemList();
|
||||
@@ -94,6 +94,62 @@ export default class AdminRegistry {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function allows you to change the configuration of a setting.
|
||||
*/
|
||||
setSetting(key: string, content: SettingConfigInput | ((original: SettingConfigInput) => SettingConfigInput)): this {
|
||||
if (this.state.currentExtension === null) {
|
||||
throw new Error(noActiveExtensionErrorMessage);
|
||||
}
|
||||
|
||||
const settings = this.state.data[this.state.currentExtension].settings || new ItemList();
|
||||
|
||||
if (settings.has(key)) {
|
||||
if (content instanceof Function) {
|
||||
const original = settings.get(key);
|
||||
content = content(original) as SettingConfigInternal;
|
||||
}
|
||||
|
||||
settings.setContent(key, content as SettingConfigInternal);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function allows you to change the priority of a setting.
|
||||
*/
|
||||
setSettingPriority(key: string, priority: number): this {
|
||||
if (this.state.currentExtension === null) {
|
||||
throw new Error(noActiveExtensionErrorMessage);
|
||||
}
|
||||
|
||||
const settings = this.state.data[this.state.currentExtension].settings || new ItemList();
|
||||
|
||||
if (settings.has(key)) {
|
||||
settings.setPriority(key, priority);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function allows you to remove a setting.
|
||||
*/
|
||||
removeSetting(key: string): this {
|
||||
if (this.state.currentExtension === null) {
|
||||
throw new Error(noActiveExtensionErrorMessage);
|
||||
}
|
||||
|
||||
const settings = this.state.data[this.state.currentExtension].settings || new ItemList();
|
||||
|
||||
if (settings.has(key)) {
|
||||
settings.remove(key);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function registers your permission with Flarum
|
||||
*
|
||||
@@ -125,6 +181,65 @@ export default class AdminRegistry {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function allows you to change the configuration of a permission.
|
||||
*/
|
||||
setPermission(key: string, content: PermissionConfig | ((original: PermissionConfig) => PermissionConfig), permissionType: PermissionType): this {
|
||||
if (this.state.currentExtension === null) {
|
||||
throw new Error(noActiveExtensionErrorMessage);
|
||||
}
|
||||
|
||||
const permissions = this.state.data[this.state.currentExtension].permissions || {};
|
||||
const permissionsForType = permissions[permissionType] || new ItemList();
|
||||
|
||||
if (permissionsForType.has(key)) {
|
||||
if (content instanceof Function) {
|
||||
const original = permissionsForType.get(key);
|
||||
content = content(original) as PermissionConfig;
|
||||
}
|
||||
|
||||
permissionsForType.setContent(key, content);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function allows you to change the priority of a permission.
|
||||
*/
|
||||
setPermissionPriority(key: string, permissionType: PermissionType, priority: number): this {
|
||||
if (this.state.currentExtension === null) {
|
||||
throw new Error(noActiveExtensionErrorMessage);
|
||||
}
|
||||
|
||||
const permissions = this.state.data[this.state.currentExtension].permissions;
|
||||
const permissionsForType = permissions?.[permissionType] || new ItemList();
|
||||
|
||||
if (permissionsForType.has(key)) {
|
||||
permissionsForType.setPriority(key, priority);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function allows you to remove a permission.
|
||||
*/
|
||||
removePermission(key: string, permissionType: PermissionType): this {
|
||||
if (this.state.currentExtension === null) {
|
||||
throw new Error(noActiveExtensionErrorMessage);
|
||||
}
|
||||
|
||||
const permissions = this.state.data[this.state.currentExtension].permissions;
|
||||
const permissionsForType = permissions?.[permissionType] || new ItemList();
|
||||
|
||||
if (permissionsForType.has(key)) {
|
||||
permissionsForType.remove(key);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the default extension page with a custom component.
|
||||
* This component would typically extend ExtensionPage
|
||||
|
@@ -39,6 +39,7 @@ import IExtender from './extenders/IExtender';
|
||||
import AccessToken from './models/AccessToken';
|
||||
import SearchManager from './SearchManager';
|
||||
import { ColorScheme } from './components/ThemeMode';
|
||||
import { prepareSkipLinks } from './utils/a11y';
|
||||
|
||||
export type FlarumScreens = 'phone' | 'tablet' | 'desktop' | 'desktop-hd';
|
||||
|
||||
@@ -286,6 +287,8 @@ export default class Application {
|
||||
|
||||
private handledErrors: { extension: null | string; errorId: string; error: any }[] = [];
|
||||
|
||||
private beforeMounts: (() => void)[] = [];
|
||||
|
||||
public load(payload: Application['data']) {
|
||||
this.data = payload;
|
||||
this.translator.setLocale(payload.locale);
|
||||
@@ -326,7 +329,7 @@ export default class Application {
|
||||
|
||||
this.session = new Session(this.store.getById<User>('users', String(this.data.session.userId)) ?? null, this.data.session.csrfToken);
|
||||
|
||||
this.beforeMount();
|
||||
this.runBeforeMount();
|
||||
|
||||
this.mount();
|
||||
|
||||
@@ -335,8 +338,13 @@ export default class Application {
|
||||
caughtInitializationErrors.forEach((handler) => handler());
|
||||
}
|
||||
|
||||
protected beforeMount(): void {
|
||||
// ...
|
||||
public beforeMount(callback: () => void) {
|
||||
this.beforeMounts.push(callback);
|
||||
}
|
||||
|
||||
protected runBeforeMount(): void {
|
||||
this.beforeMounts.forEach((callback) => callback());
|
||||
this.beforeMounts = [];
|
||||
}
|
||||
|
||||
public bootExtensions(extensions: Record<string, { extend?: IExtender[] }>) {
|
||||
@@ -387,6 +395,8 @@ export default class Application {
|
||||
this.initColorScheme();
|
||||
|
||||
liveHumanTimes();
|
||||
|
||||
prepareSkipLinks();
|
||||
}
|
||||
|
||||
private initColorScheme(forumDefault: string | null = null): void {
|
||||
|
@@ -21,7 +21,7 @@ export default class DetailedDropdownItem<
|
||||
> extends Component<CustomAttrs> {
|
||||
view() {
|
||||
return (
|
||||
<button className="DetailedDropdownItem hasIcon" onclick={this.attrs.onclick}>
|
||||
<button type="button" className="DetailedDropdownItem hasIcon" onclick={this.attrs.onclick}>
|
||||
<Icon name={this.attrs.active ? 'fas fa-check' : 'fas'} className="Button-icon" />
|
||||
<span className="DetailedDropdownItem-content">
|
||||
<Icon name={this.attrs.icon} className="Button-icon" />
|
||||
|
@@ -123,6 +123,14 @@ export default class Dropdown<CustomAttrs extends IDropdownAttrs = IDropdownAttr
|
||||
|
||||
m.redraw();
|
||||
});
|
||||
|
||||
this.$().on('focusout', (e: JQuery.FocusOutEvent) => {
|
||||
// Check if the new focused element is outside of this dropdown
|
||||
if (!this.$().has(e.relatedTarget as Element).length) {
|
||||
this.$().trigger('hidden.bs.dropdown');
|
||||
}
|
||||
});
|
||||
// Focusing out of the dropdown should close it.
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -131,6 +139,7 @@ export default class Dropdown<CustomAttrs extends IDropdownAttrs = IDropdownAttr
|
||||
getButton(children: Mithril.ChildArray): Mithril.Vnode<any, any> {
|
||||
let button = (
|
||||
<button
|
||||
type="button"
|
||||
className={'Dropdown-toggle ' + this.attrs.buttonClassName}
|
||||
aria-haspopup="menu"
|
||||
aria-label={this.attrs.accessibleToggleLabel}
|
||||
|
@@ -45,6 +45,7 @@ export default class SplitDropdown<CustomAttrs extends ISplitDropdownAttrs = ISp
|
||||
<>
|
||||
{button}
|
||||
<button
|
||||
type="button"
|
||||
className={'Dropdown-toggle Button Button--icon ' + this.attrs.buttonClassName}
|
||||
aria-haspopup="menu"
|
||||
aria-label={this.attrs.accessibleToggleLabel}
|
||||
|
@@ -1,25 +1,65 @@
|
||||
import IExtender, { IExtensionModule } from './IExtender';
|
||||
import type AdminApplication from '../../admin/AdminApplication';
|
||||
import type { CustomExtensionPage, SettingConfigInternal } from '../../admin/utils/AdminRegistry';
|
||||
import type { CustomExtensionPage, SettingConfigInput } from '../../admin/utils/AdminRegistry';
|
||||
import type { PermissionConfig, PermissionType } from '../../admin/components/PermissionGrid';
|
||||
import type Mithril from 'mithril';
|
||||
import type { GeneralIndexItem } from '../../admin/states/GeneralSearchIndex';
|
||||
|
||||
export default class Admin implements IExtender<AdminApplication> {
|
||||
protected settings: { setting?: () => SettingConfigInternal | null; customSetting?: () => Mithril.Children; priority: number }[] = [];
|
||||
protected context: string | null;
|
||||
|
||||
protected settings: { setting?: () => SettingConfigInput | null; customSetting?: () => Mithril.Children; priority: number }[] = [];
|
||||
protected settingReplacements: { setting: string; replacement: (original: SettingConfigInput) => SettingConfigInput }[] = [];
|
||||
protected settingPriorityChanges: { setting: string; priority: number }[] = [];
|
||||
protected settingRemovals: string[] = [];
|
||||
protected permissions: { permission: () => PermissionConfig | null; type: PermissionType; priority: number }[] = [];
|
||||
protected permissionsReplacements: { permission: string; type: PermissionType; replacement: (original: PermissionConfig) => PermissionConfig }[] =
|
||||
[];
|
||||
protected permissionsPriorityChanges: { permission: string; type: PermissionType; priority: number }[] = [];
|
||||
protected permissionsRemovals: { permission: string; type: PermissionType }[] = [];
|
||||
protected customPage: CustomExtensionPage | null = null;
|
||||
protected generalIndexes: { settings?: () => GeneralIndexItem[]; permissions?: () => GeneralIndexItem[] } = {};
|
||||
|
||||
constructor(context: string | null = null) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a setting to be shown on the extension's settings page.
|
||||
*/
|
||||
setting(setting: () => SettingConfigInternal | null, priority = 0) {
|
||||
setting(setting: () => SettingConfigInput | null, priority = 0) {
|
||||
this.settings.push({ setting, priority });
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace an existing setting's configuration.
|
||||
*/
|
||||
replaceSetting(setting: string, replacement: (original: SettingConfigInput) => SettingConfigInput) {
|
||||
this.settingReplacements.push({ setting, replacement });
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the priority of an existing setting.
|
||||
*/
|
||||
setSettingPriority(setting: string, priority: number) {
|
||||
this.settingPriorityChanges.push({ setting, priority });
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a setting from the extension's settings page.
|
||||
*/
|
||||
removeSetting(setting: string) {
|
||||
this.settingRemovals.push(setting);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a custom setting to be shown on the extension's settings page.
|
||||
*/
|
||||
@@ -38,6 +78,33 @@ export default class Admin implements IExtender<AdminApplication> {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace an existing permission's configuration.
|
||||
*/
|
||||
replacePermission(permission: string, replacement: (original: PermissionConfig) => PermissionConfig, type: PermissionType) {
|
||||
this.permissionsReplacements.push({ permission, type, replacement });
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the priority of an existing permission.
|
||||
*/
|
||||
setPermissionPriority(permission: string, type: PermissionType, priority: number) {
|
||||
this.permissionsPriorityChanges.push({ permission, type, priority });
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a permission from the extension's permissions page.
|
||||
*/
|
||||
removePermission(permission: string, type: PermissionType) {
|
||||
this.permissionsRemovals.push({ permission, type });
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a custom page to be shown in the admin interface.
|
||||
*/
|
||||
@@ -57,7 +124,8 @@ export default class Admin implements IExtender<AdminApplication> {
|
||||
}
|
||||
|
||||
extend(app: AdminApplication, extension: IExtensionModule) {
|
||||
app.registry.for(extension.name);
|
||||
app.beforeMount(() => {
|
||||
app.registry.for(this.context || extension.name);
|
||||
|
||||
this.settings.forEach(({ setting, customSetting, priority }) => {
|
||||
const settingConfig = setting ? setting() : customSetting!;
|
||||
@@ -67,6 +135,18 @@ export default class Admin implements IExtender<AdminApplication> {
|
||||
}
|
||||
});
|
||||
|
||||
this.settingReplacements.forEach(({ setting, replacement }) => {
|
||||
app.registry.setSetting(setting, replacement);
|
||||
});
|
||||
|
||||
this.settingPriorityChanges.forEach(({ setting, priority }) => {
|
||||
app.registry.setSettingPriority(setting, priority);
|
||||
});
|
||||
|
||||
this.settingRemovals.forEach((setting) => {
|
||||
app.registry.removeSetting(setting);
|
||||
});
|
||||
|
||||
this.permissions.forEach(({ permission, type, priority }) => {
|
||||
const permissionConfig = permission();
|
||||
|
||||
@@ -75,6 +155,18 @@ export default class Admin implements IExtender<AdminApplication> {
|
||||
}
|
||||
});
|
||||
|
||||
this.permissionsReplacements.forEach(({ permission, type, replacement }) => {
|
||||
app.registry.setPermission(permission, replacement, type);
|
||||
});
|
||||
|
||||
this.permissionsPriorityChanges.forEach(({ permission, type, priority }) => {
|
||||
app.registry.setPermissionPriority(permission, type, priority);
|
||||
});
|
||||
|
||||
this.permissionsRemovals.forEach(({ permission, type }) => {
|
||||
app.registry.removePermission(permission, type);
|
||||
});
|
||||
|
||||
if (this.customPage) {
|
||||
app.registry.registerPage(this.customPage);
|
||||
}
|
||||
@@ -90,5 +182,6 @@ export default class Admin implements IExtender<AdminApplication> {
|
||||
app.generalIndex.add(key, callback());
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@@ -131,7 +131,7 @@ export default class Discussion extends Model {
|
||||
const items = new ItemList<Mithril.Children>();
|
||||
|
||||
if (this.isHidden()) {
|
||||
items.add('hidden', <Badge type="hidden" icon="fas fa-trash" label={app.translator.trans('core.lib.badge.hidden_tooltip')} />);
|
||||
items.add('hidden', <Badge type="hidden" icon="fas fa-trash" label={app.translator.trans('core.lib.badge.hidden_tooltip')} tabindex="0" />);
|
||||
}
|
||||
|
||||
return items;
|
||||
|
21
framework/core/js/src/common/utils/a11y.ts
Normal file
21
framework/core/js/src/common/utils/a11y.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* Fix a11y skip links by manually focusing on the href target element.
|
||||
* This prevents unwanted/unexpected reloads of the page.
|
||||
*/
|
||||
export function prepareSkipLinks() {
|
||||
document.querySelectorAll('.sr-only-focusable-custom:not([data-prepared])').forEach((el) => {
|
||||
el.addEventListener('click', function (e) {
|
||||
e.preventDefault();
|
||||
const target = el.getAttribute('href')!;
|
||||
const $target = document.querySelector(target) as HTMLElement;
|
||||
|
||||
if ($target) {
|
||||
$target.setAttribute('tabindex', '-1');
|
||||
$target.focus();
|
||||
$target.removeAttribute('tabindex');
|
||||
|
||||
$target.dataset.prepared = 'true';
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
@@ -42,9 +42,11 @@ export default class AvatarEditor extends Component {
|
||||
return (
|
||||
<div className={classList(['AvatarEditor', 'Dropdown', this.attrs.className, this.loading && 'loading', this.isDraggedOver && 'dragover'])}>
|
||||
<Avatar user={user} loading="eager" />
|
||||
<a
|
||||
<button
|
||||
type="button"
|
||||
className={user.avatarUrl() ? 'Dropdown-toggle' : 'Dropdown-toggle AvatarEditor--noAvatar'}
|
||||
title={app.translator.trans('core.forum.user.avatar_upload_tooltip')}
|
||||
ariaLabel={app.translator.trans('core.forum.user.avatar_upload_tooltip')}
|
||||
data-toggle="dropdown"
|
||||
onclick={this.quickUpload.bind(this)}
|
||||
ondragover={this.enableDragover.bind(this)}
|
||||
@@ -60,7 +62,7 @@ export default class AvatarEditor extends Component {
|
||||
) : (
|
||||
<Icon name={'fas fa-plus-circle'} />
|
||||
)}
|
||||
</a>
|
||||
</button>
|
||||
<ul className="Dropdown-menu Menu">{listItems(this.controlItems().toArray())}</ul>
|
||||
</div>
|
||||
);
|
||||
|
@@ -76,15 +76,15 @@ export default class DiscussionListItem<CustomAttrs extends IDiscussionListItemA
|
||||
viewItems(): ItemList<Mithril.Children> {
|
||||
const items = new ItemList<Mithril.Children>();
|
||||
|
||||
items.add('slidableUnderneath', this.slidableUnderneathView(), 90);
|
||||
items.add('content', this.contentView(), 80);
|
||||
|
||||
const controls = DiscussionControls.controls(this.attrs.discussion, this).toArray();
|
||||
|
||||
if (controls.length) {
|
||||
items.add('controls', this.controlsView(controls), 100);
|
||||
items.add('controls', this.controlsView(controls), 70);
|
||||
}
|
||||
|
||||
items.add('slidableUnderneath', this.slidableUnderneathView(), 90);
|
||||
items.add('content', this.contentView(), 80);
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
@@ -312,7 +312,7 @@ export default class DiscussionListItem<CustomAttrs extends IDiscussionListItemA
|
||||
className="DiscussionListItem-count"
|
||||
icon={showUnread ? [<Icon name={'fas fa-check _checkmark'} />, <Icon name={'fas fa-comment _comment'} />] : <Icon name={'far fa-comment'} />}
|
||||
label={showUnread ? abbreviateNumber(discussion.unreadCount()) : abbreviateNumber(discussion.replyCount())}
|
||||
a11yLabel={app.translator.trans(a11yKey, { count: discussion.replyCount() })}
|
||||
ariaLabel={app.translator.trans(a11yKey, { count: discussion.unreadCount() })}
|
||||
onclick={showUnread ? this.markAsRead.bind(this) : undefined}
|
||||
/>
|
||||
);
|
||||
|
@@ -2,6 +2,7 @@ import app from '../../forum/app';
|
||||
import DiscussionList from './DiscussionList';
|
||||
import Component from '../../common/Component';
|
||||
import DiscussionPage from './DiscussionPage';
|
||||
import { prepareSkipLinks } from '../../common/utils/a11y';
|
||||
|
||||
const hotEdge = (e) => {
|
||||
if (e.pageX < 10) app.pane.show();
|
||||
@@ -22,7 +23,14 @@ export default class DiscussionListPane extends Component {
|
||||
return;
|
||||
}
|
||||
|
||||
return <aside className="DiscussionListPane">{this.enoughSpace() && <DiscussionList state={this.attrs.state} />}</aside>;
|
||||
return (
|
||||
<aside className="DiscussionListPane">
|
||||
<a href="#page-main" class="sr-only sr-only-focusable-custom" oncreate={() => prepareSkipLinks()}>
|
||||
{app.translator.trans('core.forum.discussion_list.skip_discussion_list_pane')}
|
||||
</a>
|
||||
{this.enoughSpace() && <DiscussionList state={this.attrs.state} />}
|
||||
</aside>
|
||||
);
|
||||
}
|
||||
|
||||
oncreate(vnode) {
|
||||
@@ -34,7 +42,12 @@ export default class DiscussionListPane extends Component {
|
||||
// and hide the pane respectively. We also create a 10px 'hot edge' on the
|
||||
// left of the screen to activate the pane.
|
||||
const pane = app.pane;
|
||||
$list.hover(pane.show.bind(pane), pane.onmouseleave.bind(pane));
|
||||
$list.on('mouseenter', pane.show.bind(pane));
|
||||
$list.on('mouseleave', pane.onmouseleave.bind(pane));
|
||||
// a11y: when tabbing into the pane (focus) we should also show the pane.
|
||||
// and when tabbing out, we should hide the pane.
|
||||
$list.on('focus', 'a, .Button', pane.show.bind(pane));
|
||||
$list.on('blur', 'a, .Button', pane.onmouseleave.bind(pane));
|
||||
|
||||
$(document).on('mousemove', hotEdge);
|
||||
|
||||
|
@@ -1,9 +1,11 @@
|
||||
import app from '../app';
|
||||
import Component from '../../common/Component';
|
||||
import type { ComponentAttrs } from '../../common/Component';
|
||||
import type Mithril from 'mithril';
|
||||
import classList from '../../common/utils/classList';
|
||||
import ItemList from '../../common/utils/ItemList';
|
||||
import LoadingIndicator from '../../common/components/LoadingIndicator';
|
||||
import { prepareSkipLinks } from '../../common/utils/a11y';
|
||||
|
||||
export interface PageStructureAttrs extends ComponentAttrs {
|
||||
hero?: () => Mithril.Children;
|
||||
@@ -51,7 +53,11 @@ export default class PageStructure<CustomAttrs extends PageStructureAttrs = Page
|
||||
}
|
||||
|
||||
main(): Mithril.Children {
|
||||
return <div className="Page-main">{this.attrs.loading ? this.loadingItems().toArray() : this.mainItems().toArray()}</div>;
|
||||
return (
|
||||
<div className="Page-main" id="page-main">
|
||||
{this.attrs.loading ? this.loadingItems().toArray() : this.mainItems().toArray()}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
containerItems(): ItemList<Mithril.Children> {
|
||||
@@ -70,6 +76,14 @@ export default class PageStructure<CustomAttrs extends PageStructureAttrs = Page
|
||||
sidebarItems(): ItemList<Mithril.Children> {
|
||||
const items = new ItemList<Mithril.Children>();
|
||||
|
||||
items.add(
|
||||
'skipToMainContent',
|
||||
<a href="#main-content" className="sr-only sr-only-focusable-custom" oncreate={() => prepareSkipLinks()}>
|
||||
{app.translator.trans('core.forum.index.skip_to_main_content')}
|
||||
</a>,
|
||||
200
|
||||
);
|
||||
|
||||
items.add('sidebar', (this.attrs.sidebar && this.attrs.sidebar()) || null, 100);
|
||||
|
||||
return items;
|
||||
@@ -88,6 +102,10 @@ export default class PageStructure<CustomAttrs extends PageStructureAttrs = Page
|
||||
}
|
||||
|
||||
providedContent(): Mithril.Children {
|
||||
return <div className="Page-content">{this.content}</div>;
|
||||
return (
|
||||
<div className="Page-content" id="main-content">
|
||||
{this.content}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -40,6 +40,7 @@ export default class PostMeta<CustomAttrs extends IPostMetaAttrs = IPostMetaAttr
|
||||
items.add(
|
||||
'time',
|
||||
<button
|
||||
type="button"
|
||||
className={classList({
|
||||
'Button Button--text': true,
|
||||
'Dropdown-toggle Button--link': !!permalink,
|
||||
|
@@ -58,7 +58,7 @@ export default class PostStreamScrubber extends Component {
|
||||
|
||||
return (
|
||||
<div className={classNames.join(' ')}>
|
||||
<button className="Button Dropdown-toggle" data-toggle="dropdown">
|
||||
<button type="button" className="Button Dropdown-toggle" data-toggle="dropdown">
|
||||
{viewing} <Icon name={'fas fa-sort'} />
|
||||
</button>
|
||||
|
||||
|
@@ -54,7 +54,7 @@ export default class ReplyPlaceholder<CustomAttrs extends IReplyPlaceholderAttrs
|
||||
});
|
||||
|
||||
return (
|
||||
<button className="Post ReplyPlaceholder" onclick={reply}>
|
||||
<button type="button" className="Post ReplyPlaceholder" onclick={reply}>
|
||||
<div className="Post-container">
|
||||
<div className="Post-side">
|
||||
<Avatar user={app.session.user} className="Post-avatar" />
|
||||
|
@@ -20,10 +20,6 @@
|
||||
border-radius: 100%;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
span& {
|
||||
cursor: default;
|
||||
}
|
||||
}
|
||||
|
||||
.Avatar--size(@size) {
|
||||
|
@@ -199,3 +199,13 @@ blockquote ol:last-child {
|
||||
.text-colored {
|
||||
color: var(--color);
|
||||
}
|
||||
|
||||
.sr-only-focusable-custom:focus {
|
||||
clip: unset;
|
||||
width: auto;
|
||||
height: auto;
|
||||
border-width: medium;
|
||||
background: #000;
|
||||
color: #fff;
|
||||
z-index: 100;
|
||||
}
|
||||
|
@@ -136,6 +136,9 @@
|
||||
|
||||
@screen-phone-max: (@screen-tablet - 0.02);
|
||||
|
||||
@screen-small-phone: 320px;
|
||||
@screen-small-phone-max: (@screen-small-phone + 0.02);
|
||||
|
||||
@screen-tablet: 768px;
|
||||
@screen-tablet-max: (@screen-desktop - 0.02);
|
||||
|
||||
@@ -148,6 +151,7 @@
|
||||
@screen-desktop-xxxl: 3000px;
|
||||
|
||||
@phone: ~"(max-width: @{screen-phone-max})";
|
||||
@small-phone: ~"(max-width: @{screen-small-phone-max})";
|
||||
@tablet: ~"(min-width: @{screen-tablet}) and (max-width: @{screen-tablet-max})";
|
||||
@desktop: ~"(min-width: @{screen-desktop}) and (max-width: @{screen-desktop-max})";
|
||||
@desktop-hd: ~"(min-width: @{screen-desktop-hd})";
|
||||
|
@@ -15,6 +15,8 @@
|
||||
inset: 0;
|
||||
border-radius: 100%;
|
||||
background: rgba(0, 0, 0, 0.6);
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
border: 0;
|
||||
@@ -23,6 +25,7 @@
|
||||
opacity: 0.7;
|
||||
}
|
||||
&:hover .Dropdown-toggle,
|
||||
.Dropdown-toggle:focus,
|
||||
&.open .Dropdown-toggle,
|
||||
&.loading .Dropdown-toggle,
|
||||
&.dragover .Dropdown-toggle {
|
||||
|
@@ -306,7 +306,7 @@
|
||||
display: none;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
&:hover, &:focus {
|
||||
._checkmark {
|
||||
display: block;
|
||||
}
|
||||
@@ -317,3 +317,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media @small-phone {
|
||||
.DiscussionListItem-info {
|
||||
max-width: 160px;
|
||||
}
|
||||
}
|
||||
|
@@ -459,6 +459,7 @@ core:
|
||||
empty_text: It looks as though there are no discussions here.
|
||||
load_more_button: => core.ref.load_more
|
||||
replied_text: "{username} replied {ago}"
|
||||
skip_discussion_list_pane: Skip the discussion list pane
|
||||
started_text: "{username} started {ago}"
|
||||
total_replies_a11y_label: "{count, plural, one {# reply} other {# replies}}"
|
||||
unread_replies_a11y_label: "{count, plural, one {# unread reply} other {# unread replies}}. Mark unread {count, plural, one {reply} other {replies}} as read."
|
||||
@@ -496,6 +497,7 @@ core:
|
||||
meta_title_text: => core.ref.all_discussions
|
||||
refresh_tooltip: => core.ref.refresh
|
||||
start_discussion_button: => core.ref.start_a_discussion
|
||||
skip_to_main_content: Skip to main content
|
||||
toggle_sidenav_dropdown_accessible_label: Toggle navigation dropdown menu
|
||||
|
||||
# These translations are used by the sorting control above the discussion list.
|
||||
@@ -911,6 +913,10 @@ core:
|
||||
next_page_button: => core.ref.next_page
|
||||
previous_page_button: => core.ref.previous_page
|
||||
|
||||
# Translations in this namespace are displayed by the basic HTML forum layout.
|
||||
layout:
|
||||
skip_to_content: Skip to content
|
||||
|
||||
# Translations in this namespace are displayed by the Log Out confirmation interface.
|
||||
log_out:
|
||||
log_out_button: => core.ref.log_out
|
||||
|
@@ -63,7 +63,6 @@ class AdminServiceProvider extends AbstractServiceProvider
|
||||
HttpMiddleware\ReferrerPolicyHeader::class,
|
||||
HttpMiddleware\ContentTypeOptionsHeader::class,
|
||||
Middleware\DisableBrowserCache::class,
|
||||
Middleware\GatherDebugInformation::class,
|
||||
];
|
||||
});
|
||||
|
||||
|
@@ -54,9 +54,7 @@ class AdminPayload
|
||||
$document->payload['extensions'] = $this->extensions->getExtensions()->toArray();
|
||||
|
||||
$document->payload['displayNameDrivers'] = array_keys($this->container->make('flarum.user.display_name.supported_drivers'));
|
||||
$document->payload['slugDrivers'] = array_map(function ($resourceDrivers) {
|
||||
return array_keys($resourceDrivers);
|
||||
}, $this->container->make('flarum.http.slugDrivers'));
|
||||
$document->payload['slugDrivers'] = array_map(array_keys(...), $this->container->make('flarum.http.slugDrivers'));
|
||||
$document->payload['searchDrivers'] = $this->getSearchDrivers();
|
||||
|
||||
$document->payload['phpVersion'] = $this->appInfo->identifyPHPVersion();
|
||||
|
@@ -1,66 +0,0 @@
|
||||
<?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\Admin\Middleware;
|
||||
|
||||
use Flarum\Settings\SettingsRepositoryInterface;
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Psr\Http\Server\MiddlewareInterface as Middleware;
|
||||
use Psr\Http\Server\RequestHandlerInterface as Handler;
|
||||
|
||||
class GatherDebugInformation implements Middleware
|
||||
{
|
||||
public function __construct(protected SettingsRepositoryInterface $settings)
|
||||
{
|
||||
}
|
||||
|
||||
public function process(Request $request, Handler $handler): Response
|
||||
{
|
||||
$this->upsertWebUser();
|
||||
|
||||
$this->upsertOpCacheStatus();
|
||||
|
||||
return $handler->handle($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read current web user, so we can compare that against CLI executions,
|
||||
* these often cause file permission issues.
|
||||
*/
|
||||
public function upsertWebUser(): void
|
||||
{
|
||||
$user = $this->settings->get('core.debug.web_user');
|
||||
$currentUser = get_current_user();
|
||||
|
||||
if ($user !== $currentUser) {
|
||||
$this->settings->set(
|
||||
'core.debug.web_user',
|
||||
$currentUser
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the opcache situation, this is only visible in web.
|
||||
* Cli has opcache disabled by default.
|
||||
*/
|
||||
public function upsertOpCacheStatus(): void
|
||||
{
|
||||
$opcache = $this->settings->get('core.debug.opcache');
|
||||
$opcacheStatus = function_exists('opcache_get_configuration') && opcache_get_configuration() !== false ? 'on' : 'off';
|
||||
|
||||
if ($opcache !== $opcacheStatus) {
|
||||
$this->settings->set(
|
||||
'core.debug.opcache',
|
||||
$opcacheStatus
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
@@ -108,27 +108,27 @@ class Context extends BaseContext
|
||||
return $this->parameters[$key] ?? $default;
|
||||
}
|
||||
|
||||
public function creating(string|null $resource = null): bool
|
||||
public function creating(?string $resource = null): bool
|
||||
{
|
||||
return $this->endpoint instanceof Endpoint\Create && (! $resource || is_a($this->collection, $resource));
|
||||
}
|
||||
|
||||
public function updating(string|null $resource = null): bool
|
||||
public function updating(?string $resource = null): bool
|
||||
{
|
||||
return $this->endpoint instanceof Endpoint\Update && (! $resource || is_a($this->collection, $resource));
|
||||
}
|
||||
|
||||
public function deleting(string|null $resource = null): bool
|
||||
public function deleting(?string $resource = null): bool
|
||||
{
|
||||
return $this->endpoint instanceof Endpoint\Delete && (! $resource || is_a($this->collection, $resource));
|
||||
}
|
||||
|
||||
public function showing(string|null $resource = null): bool
|
||||
public function showing(?string $resource = null): bool
|
||||
{
|
||||
return $this->endpoint instanceof Endpoint\Show && (! $resource || is_a($this->collection, $resource));
|
||||
}
|
||||
|
||||
public function listing(string|null $resource = null): bool
|
||||
public function listing(?string $resource = null): bool
|
||||
{
|
||||
return $this->endpoint instanceof Endpoint\Index && (! $resource || is_a($this->collection, $resource));
|
||||
}
|
||||
|
@@ -27,7 +27,7 @@ class UninstallExtensionController extends AbstractDeleteController
|
||||
|
||||
$name = Arr::get($request->getQueryParams(), 'name');
|
||||
|
||||
if ($this->extensions->getExtension($name) == null) {
|
||||
if ($this->extensions->getExtension($name) === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@@ -103,7 +103,7 @@ trait ExtractsListingParams
|
||||
return [
|
||||
'filter' => RequestUtil::extractFilter($context->request),
|
||||
'sort' => RequestUtil::extractSort($context->request, $this->defaultSort, $this->getAvailableSorts($context)),
|
||||
'limit' => $limit = (RequestUtil::extractLimit($context->request, $this->limit, $this->maxLimit) ?? null),
|
||||
'limit' => $limit = RequestUtil::extractLimit($context->request, $this->limit, $this->maxLimit),
|
||||
'offset' => RequestUtil::extractOffset($context->request, $limit),
|
||||
];
|
||||
}
|
||||
|
@@ -60,7 +60,7 @@ trait HasAuthorization
|
||||
: ($this->authenticated)($context));
|
||||
}
|
||||
|
||||
public function getAuthorized(Context $context): string|null
|
||||
public function getAuthorized(Context $context): ?string
|
||||
{
|
||||
if (! is_callable($this->ability)) {
|
||||
return $this->ability;
|
||||
|
@@ -13,7 +13,6 @@ use Closure;
|
||||
use Flarum\Api\Resource\AbstractDatabaseResource;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\Relation;
|
||||
use Illuminate\Support\Str;
|
||||
use Tobyz\JsonApiServer\Context;
|
||||
|
||||
@@ -147,13 +146,10 @@ trait HasEagerLoading
|
||||
|
||||
protected function compileWhereEagerLoads(Context $context): array
|
||||
{
|
||||
$relations = [];
|
||||
|
||||
foreach ($this->loadRelationWhere as $name => $callable) {
|
||||
$relations[$name] = function ($query) use ($callable, $context) {
|
||||
$callable($query, $context);
|
||||
};
|
||||
}
|
||||
$relations = array_map(
|
||||
callback: fn ($callable) => fn ($query) => $callable($query, $context),
|
||||
array: $this->loadRelationWhere
|
||||
);
|
||||
|
||||
return $relations;
|
||||
}
|
||||
|
@@ -89,7 +89,7 @@ class Create extends Endpoint
|
||||
final protected function fillDefaultValues(Context $context, array &$data): void
|
||||
{
|
||||
foreach ($context->fields($context->resource) as $field) {
|
||||
if (! has_value($data, $field) && ($default = $field->default)) {
|
||||
if (($default = $field->default) && ! has_value($data, $field)) {
|
||||
set_value($data, $field, $default($context->withField($field)));
|
||||
}
|
||||
}
|
||||
|
@@ -43,7 +43,6 @@ class Index extends Endpoint
|
||||
use HasCustomHooks;
|
||||
|
||||
public Closure $paginationResolver;
|
||||
public ?string $defaultSort = null;
|
||||
protected ?Closure $query = null;
|
||||
|
||||
public function __construct(string $name)
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user