mirror of
https://github.com/discourse/discourse.git
synced 2024-11-27 12:13:37 +08:00
Add d-link
component to simplify menu markup
This commit is contained in:
parent
6fb69d4434
commit
c36fdccab2
62
app/assets/javascripts/discourse/components/d-link.js.es6
Normal file
62
app/assets/javascripts/discourse/components/d-link.js.es6
Normal file
|
@ -0,0 +1,62 @@
|
|||
import computed from 'ember-addons/ember-computed-decorators';
|
||||
import { iconHTML } from 'discourse/helpers/fa-icon';
|
||||
import DiscourseURL from 'discourse/lib/url';
|
||||
|
||||
export default Ember.Component.extend({
|
||||
tagName: 'a',
|
||||
attributeBindings: ['translatedTitle:title', 'translatedTitle:aria-title', 'href'],
|
||||
|
||||
@computed('path')
|
||||
href(path) {
|
||||
if (path) { return path; }
|
||||
|
||||
const route = this.get('route');
|
||||
if (route) {
|
||||
const router = this.container.lookup('router:main');
|
||||
if (router && router.router) {
|
||||
return router.router.generate(route, this.get('model'));
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
},
|
||||
|
||||
@computed("title", "label")
|
||||
translatedTitle(title, label) {
|
||||
const text = title || label;
|
||||
if (text) return I18n.t(text);
|
||||
},
|
||||
|
||||
click() {
|
||||
const action = this.get('action');
|
||||
if (action) {
|
||||
this.sendAction('action');
|
||||
return false;
|
||||
}
|
||||
const href = this.get('href');
|
||||
if (href) {
|
||||
DiscourseURL.routeTo(href);
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
render(buffer) {
|
||||
if (!!this.get('template')) {
|
||||
return this._super(buffer);
|
||||
}
|
||||
|
||||
const icon = this.get('icon');
|
||||
if (icon) {
|
||||
buffer.push(iconHTML(icon));
|
||||
}
|
||||
|
||||
const label = this.get('label');
|
||||
if (label) {
|
||||
if (icon) { buffer.push(" "); }
|
||||
|
||||
buffer.push(I18n.t(label));
|
||||
}
|
||||
}
|
||||
|
||||
});
|
|
@ -5,7 +5,16 @@ export default Ember.Component.extend({
|
|||
classNames: ['user-menu'],
|
||||
notifications: null,
|
||||
loadingNotifications: false,
|
||||
myNotificationsUrl: url('/my/notifications'),
|
||||
notificationsPath: url('currentUser.path', '%@/notifications'),
|
||||
bookmarksPath: url('currentUser.path', '%@/activity/bookmarks'),
|
||||
messagesPath: url('currentUser.path', '%@/messages'),
|
||||
preferencesPath: url('currentUser.path', '%@/preferences'),
|
||||
|
||||
@computed('allowAnon', 'isAnon')
|
||||
showEnableAnon(allowAnon, isAnon) { return allowAnon && !isAnon; },
|
||||
|
||||
@computed('allowAnon', 'isAnon')
|
||||
showDisableAnon(allowAnon, isAnon) { return allowAnon && isAnon; },
|
||||
|
||||
@observes('visible')
|
||||
_loadNotifications(visible) {
|
||||
|
|
|
@ -1,45 +1,41 @@
|
|||
{{#menu-panel visible=visible}}
|
||||
<div class='menu-links-header'>
|
||||
<ul class='menu-links-row'>
|
||||
<li>{{#link-to 'user' currentUser class="user-activity-link" }}<i class='fa fa-user'></i> {{i18n 'user.profile'}}{{/link-to}}</li>
|
||||
<li>{{d-link route='user' model=currentUser class="user-activity-link" icon="user" label="user.profile"}}</li>
|
||||
|
||||
{{#if allowAnon}}
|
||||
{{#if isAnon}}
|
||||
<li>
|
||||
<a href {{action 'toggleAnon'}}>{{i18n 'switch_from_anon'}}</a>
|
||||
</li>
|
||||
{{/if}}
|
||||
{{#if showDisableAnon}}
|
||||
<li>{{d-link action="toggleAnon" label="switch_from_anon"}}</li>
|
||||
{{/if}}
|
||||
<li class='glyphs'>
|
||||
<a href="{{currentUser.path}}/activity/bookmarks" title="{{i18n 'user.bookmarks'}}" aria-label="{{i18n 'user.bookmarks'}}"><i class='fa fa-bookmark'></i></a>
|
||||
<a href="{{currentUser.path}}/messages" title="{{i18n 'user.private_messages'}}" aria-label="{{i18n 'user.private_messages'}}"><i class='fa fa-envelope'></i></a>
|
||||
{{#if allowAnon}}
|
||||
{{#unless isAnon}}
|
||||
<a href {{action 'toggleAnon'}} title="{{i18n 'switch_to_anon'}}" aria-label="{{i18n 'switch_to_anon'}}"><i class='fa fa-user-secret'></i></a>
|
||||
{{/unless}}
|
||||
{{d-link path=bookmarksPath title="user.bookmarks" icon="bookmark"}}
|
||||
{{d-link path=messagesPath title="user.private_messages" icon="envelope"}}
|
||||
{{#if showEnableAnon}}
|
||||
{{d-link action="toggleAnon" title="switch_to_anon" icon="user-secret"}}
|
||||
{{/if}}
|
||||
<a href="{{currentUser.path}}/preferences" title="{{i18n 'user.preferences'}}" aria-label="{{i18n 'user.preferences'}}"><i class='fa fa-gear'></i></a>
|
||||
{{d-link path=preferencesPath title="user.preferences" icon="gear"}}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class='notifications'>
|
||||
{{#conditional-loading-spinner condition=loadingNotifications containerClass="spinner-container"}}
|
||||
<hr style="margin:3px 0" />
|
||||
<hr>
|
||||
{{#if notifications}}
|
||||
<ul>
|
||||
{{#each notifications as |n|}}
|
||||
{{notification-item notification=n}}
|
||||
{{/each}}
|
||||
<li class="read last">
|
||||
<a href={{myNotificationsUrl}}>{{i18n 'notifications.more'}}…</a>
|
||||
{{#d-link path=notificationsPath}}
|
||||
{{i18n 'notifications.more'}}…
|
||||
{{/d-link}}
|
||||
</li>
|
||||
</ul>
|
||||
{{/if}}
|
||||
{{/conditional-loading-spinner}}
|
||||
{{#if siteSettings.show_logout_in_header}}
|
||||
<hr style="margin:3px 0" />
|
||||
<a href {{action 'logout'}} class='logout'>{{fa-icon "sign-out"}} {{i18n 'user.log_out'}}</a>
|
||||
<hr>
|
||||
{{d-link action="logout" class="logout" icon="sign-out" label="user.log_out"}}
|
||||
{{/if}}
|
||||
{{plugin-outlet "user-menu-bottom"}}
|
||||
</div>
|
||||
|
|
61
test/javascripts/components/d-link-test.js.es6
Normal file
61
test/javascripts/components/d-link-test.js.es6
Normal file
|
@ -0,0 +1,61 @@
|
|||
import componentTest from 'helpers/component-test';
|
||||
|
||||
moduleForComponent('d-link', {integration: true});
|
||||
|
||||
componentTest('basic usage', {
|
||||
template: '{{d-link path="/wat" title="user.preferences" icon="gear"}}',
|
||||
test(assert) {
|
||||
const $a = this.$('a');
|
||||
|
||||
assert.ok($a.length);
|
||||
assert.equal($a.attr('href'), '/wat');
|
||||
assert.equal($a.attr('title'), I18n.t('user.preferences'));
|
||||
assert.equal($a.attr('aria-title'), I18n.t('user.preferences'));
|
||||
assert.ok(this.$('i.fa-gear', $a).length, 'shows the icon');
|
||||
}
|
||||
});
|
||||
|
||||
componentTest('with a label', {
|
||||
template: '{{d-link label="user.preferences"}}',
|
||||
test(assert) {
|
||||
const $a = this.$('a');
|
||||
assert.equal($a.text(), I18n.t('user.preferences'));
|
||||
assert.equal($a.attr('title'), I18n.t('user.preferences'));
|
||||
assert.equal($a.attr('aria-title'), I18n.t('user.preferences'));
|
||||
}
|
||||
});
|
||||
|
||||
componentTest('with a label and icon', {
|
||||
template: '{{d-link label="user.preferences" icon="gear"}}',
|
||||
test(assert) {
|
||||
const $a = this.$('a');
|
||||
assert.ok(this.$('i.fa-gear', $a).length, 'shows the icon');
|
||||
assert.equal($a.text(), ` ${I18n.t('user.preferences')}`, "includes a space");
|
||||
assert.equal($a.attr('title'), I18n.t('user.preferences'));
|
||||
assert.equal($a.attr('aria-title'), I18n.t('user.preferences'));
|
||||
}
|
||||
});
|
||||
|
||||
componentTest('block form', {
|
||||
template: '{{#d-link path="/test"}}hello world{{/d-link}}',
|
||||
test(assert) {
|
||||
const $a = this.$('a');
|
||||
assert.equal($a.attr('href'), '/test');
|
||||
assert.equal($a.text(), 'hello world');
|
||||
}
|
||||
});
|
||||
|
||||
componentTest('with an action', {
|
||||
template: '{{d-link action="doThing" title="user.preferences" icon="gear"}}',
|
||||
test(assert) {
|
||||
expect(2);
|
||||
|
||||
assert.ok(this.$('a[href]').length, 'href attribute is present to help with styling');
|
||||
|
||||
this.on('doThing', () => {
|
||||
assert.ok(true, 'it fired the action');
|
||||
});
|
||||
|
||||
click('a')
|
||||
}
|
||||
});
|
Loading…
Reference in New Issue
Block a user