-
-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
9b404b9
commit 1bcfee8
Showing
5 changed files
with
338 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,55 @@ | ||
import app from 'flarum/forum/app'; | ||
import Model from 'flarum/common/Model'; | ||
import User from 'flarum/common/Model'; | ||
import computed from 'flarum/common/utils/computed'; | ||
|
||
export default class Poll extends Model { | ||
//TMP | ||
title() { | ||
return Model.attribute<string>('title').call(this); | ||
} | ||
slug() { | ||
return Model.attribute<string>('slug').call(this); | ||
} | ||
|
||
createdAt() { | ||
return Model.attribute<Date | undefined, string | undefined>('createdAt', Model.transformDate).call(this); | ||
} | ||
user() { | ||
return Model.hasOne<User | null>('user').call(this); | ||
} | ||
|
||
voteCount() { | ||
return Model.attribute<number>('voteCount').call(this); | ||
} | ||
|
||
// TODO: These two don't make sense as of now | ||
isUnread() { | ||
return computed<boolean, this>('unreadCount', (unreadCount) => !!unreadCount).call(this); | ||
} | ||
isRead() { | ||
return computed<boolean, this>('unreadCount', (unreadCount) => !!(app.session.user && !unreadCount)).call(this); | ||
} | ||
|
||
hiddenAt() { | ||
return Model.attribute('hiddenAt', Model.transformDate).call(this); | ||
} | ||
hiddenUser() { | ||
return Model.hasOne<User | null>('hiddenUser').call(this); | ||
} | ||
isHidden() { | ||
return computed<boolean, this>('hiddenAt', (hiddenAt) => !!hiddenAt).call(this); | ||
} | ||
|
||
canVote() { | ||
return Model.attribute<boolean | undefined>('canVote').call(this); | ||
} | ||
canRename() { | ||
return Model.attribute<boolean | undefined>('canRename').call(this); | ||
} | ||
canHide() { | ||
return Model.attribute<boolean | undefined>('canHide').call(this); | ||
} | ||
canDelete() { | ||
return Model.attribute<boolean | undefined>('canDelete').call(this); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import app from 'flarum/forum/app'; | ||
import Component from 'flarum/common/Component'; | ||
import PollListItem from './PollListItem'; | ||
import Button from 'flarum/common/components/Button'; | ||
import LoadingIndicator from 'flarum/common/components/LoadingIndicator'; | ||
import Placeholder from 'flarum/common/components/Placeholder'; | ||
import classList from 'flarum/common/utils/classList'; | ||
|
||
/** | ||
* The `PollList` component displays a list of polls. | ||
*/ | ||
export default class PollList extends Component { | ||
view() { | ||
/** | ||
* @type {import('../../states/PollListState').default} | ||
*/ | ||
const state = this.attrs.state; | ||
|
||
const params = state.getParams(); | ||
const isLoading = state.isInitialLoading() || state.isLoadingNext(); | ||
|
||
let loading; | ||
|
||
if (isLoading) { | ||
loading = <LoadingIndicator />; | ||
} else if (state.hasNext()) { | ||
loading = ( | ||
<Button className="Button" onclick={state.loadNext.bind(state)}> | ||
{/* TODO: IS THIS THE RIGHT KEY? MAYBE WE SHOULD MAKE A NEW ONE? */} | ||
{app.translator.trans('core.forum.discussion_list.load_more_button')} | ||
</Button> | ||
); | ||
} | ||
|
||
if (state.isEmpty()) { | ||
{ | ||
/* TODO: IS THIS THE RIGHT KEY? MAYBE WE SHOULD MAKE A NEW ONE? */ | ||
} | ||
const text = app.translator.trans('core.forum.discussion_list.empty_text'); | ||
return ( | ||
<div className="PollList"> | ||
<Placeholder text={text} /> | ||
</div> | ||
); | ||
} | ||
|
||
const pageSize = state.pageSize; | ||
|
||
return ( | ||
<div className={classList('PollList', { 'PollList--searchResults': state.isSearchResults() })}> | ||
<ul aria-busy={isLoading} className="PollList-polls"> | ||
{state.getPages().map((pg) => { | ||
return pg.items.map((poll) => ( | ||
<li key={poll.id()} data-id={poll.id()}> | ||
<PollListItem poll={poll} params={params} /> | ||
</li> | ||
)); | ||
})} | ||
</ul> | ||
<div className="PollList-loadMore">{loading}</div> | ||
</div> | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,193 @@ | ||
import * as Mithril from 'mithril'; | ||
import app from 'flarum/forum/app'; | ||
import Component, { ComponentAttrs } from 'flarum/common/Component'; | ||
import type Poll from '../../../common/models/Poll'; | ||
import type { PollListParams } from '../../states/PollListState'; | ||
import SubtreeRetainer from 'flarum/common/utils/SubtreeRetainer'; | ||
import classList from 'flarum/common/utils/classList'; | ||
import Dropdown from 'flarum/common/components/Dropdown'; | ||
import Link from 'flarum/common/components/Link'; | ||
import highlight from 'flarum/common/helpers/highlight'; | ||
import slidable from 'flarum/forum/utils/slidable'; | ||
import icon from 'flarum/common/helpers/icon'; | ||
import PollPage from './PollPage'; | ||
import abbreviateNumber from 'flarum/common/utils/abbreviateNumber'; | ||
|
||
export interface IPollListItemAttrs extends ComponentAttrs { | ||
poll: Poll; | ||
params: PollListParams; | ||
} | ||
|
||
/** | ||
* The `PollListItem` component shows a single poll in the | ||
* poll list. | ||
*/ | ||
export default class PollListItem<CustomAttrs extends IPollListItemAttrs = IPollListItemAttrs> extends Component<CustomAttrs> { | ||
/** | ||
* Ensures that the poll will not be redrawn | ||
* unless new data comes in. | ||
*/ | ||
subtree!: SubtreeRetainer; | ||
|
||
highlightRegExp?: RegExp; | ||
|
||
oninit(vnode: Mithril.Vnode<CustomAttrs, this>) { | ||
super.oninit(vnode); | ||
|
||
this.subtree = new SubtreeRetainer( | ||
() => this.attrs.poll.freshness, | ||
() => { | ||
const time = app.session.user && app.session.user.markedAllAsReadAt(); | ||
return time && time.getTime(); | ||
}, | ||
() => this.active() | ||
); | ||
} | ||
|
||
elementAttrs() { | ||
return { | ||
className: classList('PollListItem', { | ||
active: this.active(), | ||
'PollListItem--hidden': this.attrs.poll.isHidden(), | ||
Slidable: 'ontouchstart' in window, | ||
}), | ||
}; | ||
} | ||
|
||
view() { | ||
const poll = this.attrs.poll; | ||
|
||
// TODO IMPLEMENT POLLCONTROLS | ||
//const controls = PollControls.controls(poll, this).toArray(); | ||
const attrs = this.elementAttrs(); | ||
|
||
return ( | ||
<div {...attrs}> | ||
{/* {this.controlsView(controls)} */} | ||
{this.contentView()} | ||
{this.slidableUnderneathView()} | ||
</div> | ||
); | ||
} | ||
|
||
controlsView(controls: Mithril.ChildArray): Mithril.Children { | ||
return ( | ||
!!controls.length && ( | ||
<Dropdown | ||
icon="fas fa-ellipsis-v" | ||
className="PollListItem-controls" | ||
buttonClassName="Button Button--icon Button--flat" | ||
accessibleToggleLabel={app.translator.trans('fof-polls.forum.poll_controls.toggle_dropdown_accessible_label')} | ||
> | ||
{controls} | ||
</Dropdown> | ||
) | ||
); | ||
} | ||
|
||
slidableUnderneathView(): Mithril.Children { | ||
const poll = this.attrs.poll; | ||
const isUnread = poll.isUnread(); | ||
|
||
return ( | ||
<span | ||
className={classList('Slidable-underneath Slidable-underneath--left Slidable-underneath--elastic', { disabled: !isUnread })} | ||
onclick={this.markAsRead.bind(this)} | ||
> | ||
{icon('fas fa-check')} | ||
</span> | ||
); | ||
} | ||
|
||
contentView(): Mithril.Children { | ||
const poll = this.attrs.poll; | ||
// const isUnread = poll.isUnread(); | ||
// const isRead = poll.isRead(); | ||
|
||
return ( | ||
// <div className={classList('PollListItem-content', 'Slidable-content', { unread: isUnread, read: isRead })}> | ||
<div className={classList('PollListItem-content')}> | ||
{/* {this.authorAvatarView()} | ||
{this.badgesView()} */} | ||
{this.mainView()} | ||
{this.voteCountItem()} | ||
</div> | ||
); | ||
} | ||
|
||
mainView(): Mithril.Children { | ||
const poll = this.attrs.poll; | ||
|
||
return ( | ||
<Link href={app.route.poll(poll)} className="PollListItem-main"> | ||
<h2 className="PollListItem-title">{highlight(poll.title(), this.highlightRegExp)}</h2> | ||
{/* <ul className="PollListItem-info">{listItems(this.infoItems().toArray())}</ul> */} | ||
</Link> | ||
); | ||
} | ||
|
||
oncreate(vnode: Mithril.VnodeDOM<CustomAttrs, this>) { | ||
super.oncreate(vnode); | ||
|
||
// If we're on a touch device, set up the discussion row to be slidable. | ||
// This allows the user to drag the row to either side of the screen to | ||
// reveal controls. | ||
if ('ontouchstart' in window) { | ||
const slidableInstance = slidable(this.element); | ||
|
||
this.$('.PollListItem-controls').on('hidden.bs.dropdown', () => slidableInstance.reset()); | ||
} | ||
} | ||
|
||
onbeforeupdate(vnode: Mithril.VnodeDOM<CustomAttrs, this>) { | ||
super.onbeforeupdate(vnode); | ||
|
||
return this.subtree.needsRebuild(); | ||
} | ||
|
||
/** | ||
* Determine whether or not the discussion is currently being viewed. | ||
*/ | ||
active() { | ||
return app.current.matches(PollPage, { poll: this.attrs.poll }); | ||
} | ||
|
||
/** | ||
* Mark the poll as read. | ||
*/ | ||
markAsRead() { | ||
const poll = this.attrs.poll; | ||
|
||
if (poll.isUnread()) { | ||
poll.save({ lastVotedNumber: poll.voteCount() }); | ||
m.redraw(); | ||
} | ||
} | ||
|
||
voteCountItem() { | ||
const poll = this.attrs.poll; | ||
const isUnread = poll.isUnread(); | ||
|
||
if (isUnread) { | ||
return ( | ||
<button className="Button--ua-reset PollListItem-count" onclick={this.markAsRead.bind(this)}> | ||
<span aria-hidden="true">{abbreviateNumber(poll.voteCount())}</span> | ||
|
||
<span className="visually-hidden"> | ||
{app.translator.trans('core.forum.discussion_list.unread_replies_a11y_label', { count: poll.voteCount() })} | ||
</span> | ||
</button> | ||
); | ||
} | ||
|
||
return ( | ||
<span className="PollListItem-count"> | ||
<span aria-hidden="true">{abbreviateNumber(poll.voteCount())}</span> | ||
|
||
<span className="visually-hidden"> | ||
{app.translator.trans('fof-polls.forum.poll_list.total_votes_a11y_label', { count: poll.voteCount() })} | ||
</span> | ||
</span> | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import * as Mithril from 'mithril'; | ||
import app from 'flarum/forum/app'; | ||
import Page from 'flarum/common/components/Page'; | ||
|
||
export default class PollPage extends Page { | ||
view(): Mithril.Children { | ||
return <p>PollPage</p>; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters