Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mithril 2 update #93

Merged
merged 28 commits into from
Sep 24, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
8852564
update: forum/index
askvortsov1 Aug 13, 2020
6a4d258
update admin/addTagsPane
askvortsov1 Aug 13, 2020
85a1bdc
update admin/addTagsPermissionScope
askvortsov1 Aug 13, 2020
3f934e0
update: admin/components/EditTagModal
askvortsov1 Aug 13, 2020
f222abd
update: admin/components/TagSettingsModal
askvortsov1 Aug 13, 2020
88f09f4
update: admin/components/TagsPage
askvortsov1 Aug 13, 2020
58dc866
update: common/helpers/tagLabel
askvortsov1 Aug 13, 2020
b1d3843
update: forum/addTagComposer
askvortsov1 Aug 13, 2020
b043294
update: forum/addTagControl
askvortsov1 Aug 13, 2020
05748e6
update: forum/addTagFilter
askvortsov1 Aug 13, 2020
8692652
update: forum/addTagLabels
askvortsov1 Aug 13, 2020
20d5985
update: forum/addTagList
askvortsov1 Aug 13, 2020
329a32d
update: forum/components/TagHero
askvortsov1 Aug 13, 2020
6292885
update: forum/components/TagLinkButton
askvortsov1 Aug 13, 2020
e7c8340
update: forum/components/TagsPage
askvortsov1 Aug 13, 2020
7b992f8
update: forum/components/DiscussionTaggedPost
askvortsov1 Aug 13, 2020
312eed1
update: forum/components/TagDiscussionModal
askvortsov1 Aug 13, 2020
b3cca7e
fix: forum/addTagComposer (instantiate tags as empty list when creati…
askvortsov1 Aug 13, 2020
192b8cf
initAttrs is now static again
askvortsov1 Aug 16, 2020
2144d8b
Default tags for discussion composer shold be an empty list if not de…
askvortsov1 Aug 16, 2020
6657990
Rename key, move comment
askvortsov1 Aug 16, 2020
93980d6
Revert unnecessary JSX
askvortsov1 Aug 16, 2020
174d5db
Revert unnecessary syntax change
askvortsov1 Aug 16, 2020
16bd702
Extend setTitle instead of overriding so we don't miss out on setTitl…
askvortsov1 Aug 28, 2020
520e1a7
Fix use of forbidden "tag" attr
askvortsov1 Sep 3, 2020
5e519fc
Account for possibly undefined fields.tags
askvortsov1 Sep 9, 2020
75a2b0b
Further account for undefined fields.tags
askvortsov1 Sep 9, 2020
44763b1
Pass a child into TagLinkButton so that SelectDropdown works.
askvortsov1 Sep 10, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions js/src/admin/addTagsPane.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,15 @@ import AdminLinkButton from 'flarum/components/AdminLinkButton';
import TagsPage from './components/TagsPage';

export default function() {
app.routes.tags = {path: '/tags', component: TagsPage.component()};
app.routes.tags = {path: '/tags', component: TagsPage};

app.extensionSettings['flarum-tags'] = () => m.route(app.route('tags'));
app.extensionSettings['flarum-tags'] = () => m.route.set(app.route('tags'));

extend(AdminNav.prototype, 'items', items => {
items.add('tags', AdminLinkButton.component({
href: app.route('tags'),
icon: 'fas fa-tags',
children: app.translator.trans('flarum-tags.admin.nav.tags_button'),
description: app.translator.trans('flarum-tags.admin.nav.tags_text')
}));
}, app.translator.trans('flarum-tags.admin.nav.tags_button')));
});
}
17 changes: 5 additions & 12 deletions js/src/admin/addTagsPermissionScope.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,18 +48,11 @@ export default function() {
const tags = sortTags(app.store.all('tags').filter(tag => !tag.isRestricted()));

if (tags.length) {
items.add('tag', Dropdown.component({
className: 'Dropdown--restrictByTag',
buttonClassName: 'Button Button--text',
label: app.translator.trans('flarum-tags.admin.permissions.restrict_by_tag_heading'),
icon: 'fas fa-plus',
caretIcon: null,
children: tags.map(tag => Button.component({
icon: true,
children: [tagIcon(tag, {className: 'Button-icon'}), ' ', tag.name()],
onclick: () => tag.save({isRestricted: true})
}))
}));
items.add('tag', <Dropdown className='Dropdown--restrictByTag' buttonClassName='Button Button--text' label={app.translator.trans('flarum-tags.admin.permissions.restrict_by_tag_heading')} icon='fas fa-plus' caretIcon={null}>
{tags.map(tag => <Button icon={true} onclick={() => tag.save({ isRestricted: true })}>
{[tagIcon(tag, { className: 'Button-icon' }), ' ', tag.name()]}
</Button>)}
</Dropdown>);
}
});
}
31 changes: 15 additions & 16 deletions js/src/admin/components/EditTagModal.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,17 @@ import tagLabel from '../../common/helpers/tagLabel';
* to create or edit a tag.
*/
export default class EditTagModal extends Modal {
init() {
super.init();
oninit(vnode) {
super.oninit(vnode);

this.tag = this.props.tag || app.store.createRecord('tags');
this.tag = this.attrs.model || app.store.createRecord('tags');

this.name = m.prop(this.tag.name() || '');
this.slug = m.prop(this.tag.slug() || '');
this.description = m.prop(this.tag.description() || '');
this.color = m.prop(this.tag.color() || '');
this.icon = m.prop(this.tag.icon() || '');
this.isHidden = m.prop(this.tag.isHidden() || false);
this.name = m.stream(this.tag.name() || '');
this.slug = m.stream(this.tag.slug() || '');
this.description = m.stream(this.tag.description() || '');
this.color = m.stream(this.tag.color() || '');
this.icon = m.stream(this.tag.icon() || '');
this.isHidden = m.stream(this.tag.isHidden() || false);
}

className() {
Expand Down Expand Up @@ -60,31 +60,31 @@ export default class EditTagModal extends Modal {

items.add('slug', <div className="Form-group">
<label>{app.translator.trans('flarum-tags.admin.edit_tag.slug_label')}</label>
<input className="FormControl" value={this.slug()} oninput={m.withAttr('value', this.slug)}/>
<input className="FormControl" bidi={this.slug}/>
clarkwinkelmann marked this conversation as resolved.
Show resolved Hide resolved
</div>, 40);

items.add('description', <div className="Form-group">
<label>{app.translator.trans('flarum-tags.admin.edit_tag.description_label')}</label>
<textarea className="FormControl" value={this.description()} oninput={m.withAttr('value', this.description)}/>
<textarea className="FormControl" bidi={this.description}/>
</div>, 30);

items.add('color', <div className="Form-group">
<label>{app.translator.trans('flarum-tags.admin.edit_tag.color_label')}</label>
<input className="FormControl" placeholder="#aaaaaa" value={this.color()} oninput={m.withAttr('value', this.color)}/>
<input className="FormControl" placeholder="#aaaaaa" bidi={this.color}/>
</div>, 20);

items.add('icon', <div className="Form-group">
<label>{app.translator.trans('flarum-tags.admin.edit_tag.icon_label')}</label>
<div className="helpText">
{app.translator.trans('flarum-tags.admin.edit_tag.icon_text', {a: <a href="https://fontawesome.com/icons?m=free" tabindex="-1"/>})}
</div>
<input className="FormControl" placeholder="fas fa-bolt" value={this.icon()} oninput={m.withAttr('value', this.icon)}/>
<input className="FormControl" placeholder="fas fa-bolt" bidi={this.icon}/>
</div>, 10);

items.add('hidden', <div className="Form-group">
<div>
<label className="checkbox">
<input type="checkbox" value="1" checked={this.isHidden()} onchange={m.withAttr('checked', this.isHidden)}/>
<input type="checkbox" bidi={this.isHidden()}/>
{app.translator.trans('flarum-tags.admin.edit_tag.hide_label')}
</label>
</div>
Expand All @@ -95,8 +95,7 @@ export default class EditTagModal extends Modal {
type: 'submit',
className: 'Button Button--primary EditTagModal-save',
loading: this.loading,
children: app.translator.trans('flarum-tags.admin.edit_tag.submit_button')
})}
}, app.translator.trans('flarum-tags.admin.edit_tag.submit_button'))}
{this.tag.exists ? (
<button type="button" className="Button EditTagModal-delete" onclick={this.delete.bind(this)}>
{app.translator.trans('flarum-tags.admin.edit_tag.delete_tag_button')}
Expand Down
5 changes: 3 additions & 2 deletions js/src/admin/components/TagSettingsModal.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import SettingsModal from 'flarum/components/SettingsModal';
import withAttr from 'flarum/utils/withAttr';

export default class TagSettingsModal extends SettingsModal {
setMinTags(minTags, maxTags, value) {
Expand Down Expand Up @@ -32,7 +33,7 @@ export default class TagSettingsModal extends SettingsModal {
type="number"
min="0"
value={minPrimaryTags()}
oninput={m.withAttr('value', this.setMinTags.bind(this, minPrimaryTags, maxPrimaryTags))} />
oninput={withAttr('value', this.setMinTags.bind(this, minPrimaryTags, maxPrimaryTags))} />
{app.translator.trans('flarum-tags.admin.tag_settings.range_separator_text')}
<input className="FormControl"
type="number"
Expand All @@ -51,7 +52,7 @@ export default class TagSettingsModal extends SettingsModal {
type="number"
min="0"
value={minSecondaryTags()}
oninput={m.withAttr('value', this.setMinTags.bind(this, minSecondaryTags, maxSecondaryTags))} />
oninput={withAttr('value', this.setMinTags.bind(this, minSecondaryTags, maxSecondaryTags))} />
{app.translator.trans('flarum-tags.admin.tag_settings.range_separator_text')}
<input className="FormControl"
type="number"
Expand Down
147 changes: 76 additions & 71 deletions js/src/admin/components/TagsPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@ import sortTags from '../../common/utils/sortTags';

function tagItem(tag) {
return (
<li data-id={tag.id()} style={{color: tag.color()}}>
<li data-id={tag.id()} style={{ color: tag.color() }}>
<div className="TagListItem-info">
{tagIcon(tag)}
<span className="TagListItem-name">{tag.name()}</span>
{Button.component({
className: 'Button Button--link',
icon: 'fas fa-pencil-alt',
onclick: () => app.modal.show(EditTagModal, {tag})
onclick: () => app.modal.show(EditTagModal, { model: tag })
})}
</div>
{!tag.isChild() && tag.position() !== null ? (
Expand All @@ -32,6 +32,16 @@ function tagItem(tag) {
}

export default class TagsPage extends Page {
oninit(vnode) {
super.oninit(vnode);

// A regular redraw won't work here, because sortable has mucked around
// with the DOM which will confuse Mithril's diffing algorithm. Instead
// we force a full reconstruction of the DOM by changing the key, which
// makes mithril completely re-render the component on redraw.
this.forcedRefreshKey = 0;
}

view() {
return (
<div className="TagsPage">
Expand All @@ -43,18 +53,16 @@ export default class TagsPage extends Page {
{Button.component({
className: 'Button Button--primary',
icon: 'fas fa-plus',
children: app.translator.trans('flarum-tags.admin.tags.create_tag_button'),
onclick: () => app.modal.show(EditTagModal)
})}
}, app.translator.trans('flarum-tags.admin.tags.create_tag_button'))}
{Button.component({
className: 'Button',
children: app.translator.trans('flarum-tags.admin.tags.settings_button'),
onclick: () => app.modal.show(TagSettingsModal)
})}
}, app.translator.trans('flarum-tags.admin.tags.settings_button'))}
</div>
</div>
<div className="TagsPage-list">
<div className="container">
<div className="container" key={this.forcedRefreshKey} oncreate={this.onListOnCreate.bind(this)}>
<div className="TagGroup">
<label>{app.translator.trans('flarum-tags.admin.tags.primary_heading')}</label>
<ol className="TagList TagList--primary">
Expand All @@ -79,80 +87,77 @@ export default class TagsPage extends Page {
);
}

config() {
this.$('.TagList').get().map(e => {
sortable.create(e, {
group: 'tags',
animation: 150,
swapThreshold: 0.65,
dragClass: 'sortable-dragging',
ghostClass: 'sortable-placeholder',
onSort: (e) => this.onSortUpdate(e)
})
});
onListOnCreate(vnode) {
this.$('.TagList').get().map(e => {
sortable.create(e, {
group: 'tags',
animation: 150,
swapThreshold: 0.65,
dragClass: 'sortable-dragging',
ghostClass: 'sortable-placeholder',
onSort: (e) => this.onSortUpdate(e)
})
});
}

onSortUpdate(e) {
// If we've moved a tag from 'primary' to 'secondary', then we'll update
// its attributes in our local store so that when we redraw the change
// will be made.
if (e.from instanceof HTMLOListElement && e.to instanceof HTMLUListElement) {
app.store.getById('tags', e.item.getAttribute('data-id')).pushData({
attributes: {
position: null,
isChild: false
},
relationships: {parent: null}
});
}
// If we've moved a tag from 'primary' to 'secondary', then we'll update
// its attributes in our local store so that when we redraw the change
// will be made.
if (e.from instanceof HTMLOListElement && e.to instanceof HTMLUListElement) {
app.store.getById('tags', e.item.getAttribute('data-id')).pushData({
attributes: {
position: null,
isChild: false
},
relationships: { parent: null }
});
}

// Construct an array of primary tag IDs and their children, in the same
// order that they have been arranged in.
const order = this.$('.TagList--primary > li')
.map(function() {
return {
id: $(this).data('id'),
children: $(this).find('li')
.map(function() {
return $(this).data('id');
}).get()
};
}).get();
// Construct an array of primary tag IDs and their children, in the same
// order that they have been arranged in.
const order = this.$('.TagList--primary > li')
.map(function () {
return {
id: $(this).data('id'),
children: $(this).find('li')
.map(function () {
return $(this).data('id');
}).get()
};
}).get();

// Now that we have an accurate representation of the order which the
// primary tags are in, we will update the tag attributes in our local
// store to reflect this order.
order.forEach((tag, i) => {
const parent = app.store.getById('tags', tag.id);
parent.pushData({
attributes: {
position: i,
isChild: false
},
relationships: { parent: null }
});

// Now that we have an accurate representation of the order which the
// primary tags are in, we will update the tag attributes in our local
// store to reflect this order.
order.forEach((tag, i) => {
const parent = app.store.getById('tags', tag.id);
parent.pushData({
tag.children.forEach((child, j) => {
app.store.getById('tags', child).pushData({
attributes: {
position: i,
isChild: false
position: j,
isChild: true
},
relationships: {parent: null}
});

tag.children.forEach((child, j) => {
app.store.getById('tags', child).pushData({
attributes: {
position: j,
isChild: true
},
relationships: {parent}
});
relationships: { parent }
});
});
});

app.request({
url: app.forum.attribute('apiUrl') + '/tags/order',
method: 'POST',
data: {order}
});
app.request({
url: app.forum.attribute('apiUrl') + '/tags/order',
method: 'POST',
body: { order }
});

// A diff redraw won't work here, because sortable has mucked around
// with the DOM which will confuse Mithril's diffing algorithm. Instead
// we force a full reconstruction of the DOM.
m.redraw.strategy('all');
m.redraw();
this.forcedRefreshKey++;
m.redraw();
}
}
3 changes: 1 addition & 2 deletions js/src/common/helpers/tagLabel.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ export default function tagLabel(tag, attrs = {}) {

if (link) {
attrs.title = tag.description() || '';
attrs.href = app.route('tag', {tags: tag.slug()});
attrs.config = m.route;
attrs.route = app.route('tag', {tags: tag.slug()});
}
} else {
attrs.className += ' untagged';
Expand Down
Loading