uses select-box for pinned-button

This commit also moves more logic in dropdown-select-box instead of
duplicating it for notifications-options and pinned-options
This commit is contained in:
Joffrey JAFFEUX
2017-09-11 19:14:22 +02:00
committed by GitHub
parent f1639bf4f5
commit e924920bec
17 changed files with 249 additions and 108 deletions

View File

@ -10,8 +10,6 @@ export default DropdownSelectBoxComponent.extend({
generatedHeadertext: null, generatedHeadertext: null,
fullWidthOnMobile: true,
@computed @computed
content() { content() {
const items = [ const items = [
@ -45,20 +43,5 @@ export default DropdownSelectBoxComponent.extend({
_didSelectRow() { _didSelectRow() {
this.sendAction(`actionNames.${this.get("value")}`); this.sendAction(`actionNames.${this.get("value")}`);
this.set("value", null); this.set("value", null);
},
@computed
templateForRow: function() {
return (rowComponent) => {
const content = rowComponent.get("content");
return `
<div class="icons">${iconHTML(content.icon)}</div>
<div class="texts">
<span class="title">${Handlebars.escapeExpression(content.text)}</span>
<span class="desc">${Handlebars.escapeExpression(content.description)}</span>
</div>
`;
};
} }
}); });

View File

@ -6,7 +6,6 @@ import { iconHTML } from "discourse-common/lib/icon-library";
export default NotificationOptionsComponent.extend({ export default NotificationOptionsComponent.extend({
classNames: ["category-notifications-button"], classNames: ["category-notifications-button"],
classNameBindings: ["hidden:is-hidden"],
hidden: Ember.computed.or("category.deleted", "site.isMobileDevice"), hidden: Ember.computed.or("category.deleted", "site.isMobileDevice"),
i18nPrefix: "category.notifications", i18nPrefix: "category.notifications",

View File

@ -1,3 +1,4 @@
import computed from "ember-addons/ember-computed-decorators";
import SelectBoxComponent from "discourse/components/select-box"; import SelectBoxComponent from "discourse/components/select-box";
export default SelectBoxComponent.extend({ export default SelectBoxComponent.extend({
@ -5,6 +6,28 @@ export default SelectBoxComponent.extend({
wrapper: false, wrapper: false,
verticalOffset: 3, verticalOffset: 3,
collectionHeight: "auto", collectionHeight: "auto",
fullWidthOnMobile: true,
selectBoxHeaderComponent: "dropdown-select-box/dropdown-header",
selectBoxHeaderComponent: "dropdown-select-box/dropdown-header" @computed
templateForRow: function() {
return (rowComponent) => {
let template = "";
const content = rowComponent.get("content");
const icon = rowComponent.icon();
if (icon) {
template += `<div class="icons">${icon}</div>`;
}
template += `
<div class="texts">
<span class="title">${Handlebars.escapeExpression(Ember.get(content, this.get("textKey")))}</span>
<span class="desc">${Handlebars.escapeExpression(content.description)}</span>
</div>
`;
return template;
};
}
}); });

View File

@ -1,67 +1,22 @@
import { iconHTML } from 'discourse-common/lib/icon-library'; import computed from "ember-addons/ember-computed-decorators";
import computed from 'ember-addons/ember-computed-decorators';
import DropdownButton from 'discourse/components/dropdown-button';
export default DropdownButton.extend({ export default Ember.Component.extend({
descriptionKey: 'help', descriptionKey: "help",
classNames: ['pinned-options'],
title: '',
buttonExtraClasses: 'btn-icon-text',
longDescription: function(){ classNames: ["pinned-button"],
const topic = this.get('topic');
const globally = topic.get('pinned_globally') ? '_globally' : ''; classNameBindings: ["hidden:is-hidden"],
const key = 'topic_statuses.' + (topic.get('pinned') ? 'pinned' + globally : 'unpinned') + '.help';
@computed("topic.pinned_globally", "topic.pinned")
reasonText(pinnedGlobally, pinned) {
const globally = pinnedGlobally ? "_globally" : "";
const pinnedKey = pinned ? `pinned${globally}` : "unpinned";
const key = `topic_statuses.${pinnedKey}.help`;
return I18n.t(key); return I18n.t(key);
}.property('topic.pinned'),
target: Em.computed.alias('topic'),
hidden: function(){
const topic = this.get('topic');
return topic.get('deleted') || (!topic.get('pinned') && !topic.get('unpinned'));
}.property('topic.pinned', 'topic.deleted', 'topic.unpinned'),
activeItem: function(){
return this.get('topic.pinned') ? 'pinned' : 'unpinned';
}.property('topic.pinned'),
dropDownContent: function() {
const globally = this.get('topic.pinned_globally') ? '_globally' : '';
return [
{id: 'pinned',
title: I18n.t('topic_statuses.pinned' + globally + '.title'),
description: I18n.t('topic_statuses.pinned' + globally + '.help'),
icon: 'thumb-tack' },
{id: 'unpinned',
title: I18n.t('topic_statuses.unpinned.title'),
description: I18n.t('topic_statuses.unpinned.help'),
icon: 'thumb-tack',
iconClass: 'unpinned' }
];
}.property(),
@computed('topic.pinned', 'topic.pinned_globally')
text(pinned, pinnedGlobally) {
const globally = pinnedGlobally ? '_globally' : '';
const state = pinned ? 'pinned' + globally : 'unpinned';
const icon = iconHTML(
'thumb-tack',
{ tagName: 'span', class: (state === 'unpinned' ? 'unpinned' : null) }
);
return icon +
I18n.t('topic_statuses.' + state + '.title') + "<span class='caret'></span>";
}, },
clicked(id) { @computed("topic.pinned", "topic.deleted", "topic.unpinned")
const topic = this.get('topic'); hidden(pinned, deleted, unpinned) {
if(id==='unpinned'){ return deleted || (!pinned && !unpinned);
topic.clearPin();
} else {
topic.rePin();
}
} }
}); });

View File

@ -0,0 +1,70 @@
import DropdownSelectBoxComponent from "discourse/components/dropdown-select-box";
import computed from "ember-addons/ember-computed-decorators";
import { observes } from "ember-addons/ember-computed-decorators";
import { iconHTML } from "discourse-common/lib/icon-library";
export default DropdownSelectBoxComponent.extend({
classNames: ["pinned-options"],
@computed("topic.pinned")
value(pinned) {
return pinned ? "pinned" : "unpinned";
},
@observes("topic.pinned")
_pinnedChanged() {
this.set("value", this.get("topic.pinned") ? "pinned" : "unpinned");
},
@computed("topic.pinned_globally")
content(pinnedGlobally) {
const globally = pinnedGlobally ? "_globally" : "";
return [
{
id: "pinned",
text: I18n.t("topic_statuses.pinned" + globally + ".title"),
description: I18n.t('topic_statuses.pinned' + globally + '.help'),
icon: "thumb-tack"
},
{
id: "unpinned",
text: I18n.t("topic_statuses.unpinned.title"),
icon: "thumb-tack",
description: I18n.t('topic_statuses.unpinned.help'),
iconClass: "unpinned"
}
];
},
@computed("topic.pinned", "topic.pinned_globally")
icon(pinned, pinnedGlobally) {
const globally = pinnedGlobally ? "_globally" : "";
const state = pinned ? `pinned${globally}` : "unpinned";
return iconHTML(
"thumb-tack",
{ class: (state === "unpinned" ? "unpinned" : null) }
);
},
@computed("topic.pinned", "topic.pinned_globally")
generatedHeadertext(pinned, pinnedGlobally) {
const globally = pinnedGlobally ? "_globally" : "";
const state = pinned ? `pinned${globally}` : "unpinned";
const title = I18n.t(`topic_statuses.${state}.title`);
return `${title}${iconHTML("caret-down")}`.htmlSafe();
},
@observes("value")
_didSelectRow() {
const topic = this.get("topic");
if (this.get("value") === "unpinned") {
topic.clearPin();
} else {
topic.rePin();
}
}
});

View File

@ -1,17 +1,17 @@
import { on, observes } from "ember-addons/ember-computed-decorators"; import { on, observes } from "ember-addons/ember-computed-decorators";
import computed from "ember-addons/ember-computed-decorators"; import computed from "ember-addons/ember-computed-decorators";
import { iconHTML } from "discourse-common/lib/icon-library";
export default Ember.Component.extend({ export default Ember.Component.extend({
layoutName: "components/select-box", layoutName: "components/select-box",
classNames: "select-box", classNames: "select-box",
classNameBindings: ["expanded:is-expanded"], classNameBindings: ["expanded:is-expanded", "hidden:is-hidden"],
expanded: false, expanded: false,
focused: false, focused: false,
filterFocused: false, filterFocused: false,
renderBody: false, renderBody: false,
wrapper: true, wrapper: true,
hidden: false,
tabindex: 0, tabindex: 0,
scrollableParentSelector: ".modal-body", scrollableParentSelector: ".modal-body",
@ -86,9 +86,7 @@ export default Ember.Component.extend({
return (rowComponent) => { return (rowComponent) => {
let template = ""; let template = "";
if (rowComponent.get("content.icon")) { template += rowComponent.icon();
template += iconHTML(Handlebars.escapeExpression(rowComponent.get("content.icon")));
}
const text = rowComponent.get(`content.${this.get("textKey")}`); const text = rowComponent.get(`content.${this.get("textKey")}`);
template += `<p class="text">${Handlebars.escapeExpression(text)}</p>`; template += `<p class="text">${Handlebars.escapeExpression(text)}</p>`;

View File

@ -1,4 +1,5 @@
import computed from 'ember-addons/ember-computed-decorators'; import computed from 'ember-addons/ember-computed-decorators';
import { iconHTML } from "discourse-common/lib/icon-library";
export default Ember.Component.extend({ export default Ember.Component.extend({
layoutName: "components/select-box/select-box-row", layoutName: "components/select-box/select-box-row",
@ -31,6 +32,16 @@ export default Ember.Component.extend({
return shouldSelectRow(this); return shouldSelectRow(this);
}, },
icon() {
if (this.get("content.icon")) {
const iconName = this.get("content.icon");
const iconClass = this.get("content.iconClass");
return iconHTML(iconName, { class: iconClass });
}
return null;
},
mouseEnter() { mouseEnter() {
this.sendAction("onHover", this.get("content")); this.sendAction("onHover", this.get("content"));
}, },

View File

@ -4,9 +4,9 @@
type="button" type="button"
title="{{text}}"> title="{{text}}">
{{icon}} {{{icon}}}
{{#if text}} {{#if text}}
<span class="d-button-label">{{text}}</span> <span class="d-button-label">{{{text}}}</span>
{{/if}} {{/if}}
</button> </button>

View File

@ -0,0 +1,5 @@
{{pinned-options topic=topic}}
<p class="reason">
{{{reasonText}}}
</p>

View File

@ -1,7 +1,9 @@
.d-icon.regular, .d-icon.muted, .d-icon.watching-first-post { .notifications-button.notifications-button.notifications-button {
color: dark-light-choose(scale-color($primary, $lightness: 40%), scale-color($secondary, $lightness: 60%)); .d-icon.regular, .d-icon.muted, .d-icon.watching-first-post {
} color: dark-light-choose(scale-color($primary, $lightness: 40%), scale-color($secondary, $lightness: 60%));
.d-icon.tracking, .d-icon.watching { }
color: $tertiary; .d-icon.tracking, .d-icon.watching {
font-weight: normal; color: $tertiary;
font-weight: normal;
}
} }

View File

@ -3,14 +3,4 @@
min-width: auto; min-width: auto;
width: 250px; width: 250px;
} }
.select-box-row .icons {
align-self: flex-start;
width: 30px;
justify-content: center;
.d-icon {
color: dark-light-choose(scale-color($primary, $lightness: 40%), scale-color($secondary, $lightness: 60%));
}
}
} }

View File

@ -1,3 +0,0 @@
.category-notification-button.category-notification-button.is-hidden {
display: none;
}

View File

@ -16,6 +16,7 @@
background-clip: padding-box; background-clip: padding-box;
box-shadow: 0 1px 5px rgba(0,0,0,0.4); box-shadow: 0 1px 5px rgba(0,0,0,0.4);
max-width: 300px; max-width: 300px;
width: 300px;
} }
.select-box-row { .select-box-row {
@ -25,16 +26,18 @@
.icons { .icons {
display: flex; display: flex;
align-items: flex-start; align-items: flex-start;
justify-content: space-between; justify-content: center;
align-self: center; align-self: flex-start;
margin-right: 10px; margin-right: 10px;
margin-top: 2px; margin-top: 2px;
width: 30px;
.d-icon { .d-icon {
font-size: 1.286em; font-size: 1.286em;
align-self: center; align-self: center;
margin-right: 0; margin-right: 0;
opacity: 1; opacity: 1;
color: dark-light-choose(scale-color($primary, $lightness: 40%), scale-color($secondary, $lightness: 60%));
} }
} }

View File

@ -0,0 +1,44 @@
#topic-footer-buttons {
.pinned-button {
min-width: auto;
margin: 10px 0 5px 0;
&.is-hidden {
display: none;
}
.btn {
margin: 0;
}
.reason {
line-height: 16px;
margin: 0 0 0 10px;
a {
margin-left: 3px;
margin-right: 3px;
}
}
}
}
.pinned-button {
display: flex;
justify-content: flex-start;
align-items: center;
margin: 0;
min-width: auto;
.pinned-options, .reason {
display: inline-flex;
}
.pinned-options.pinned-options.pinned-options {
.select-box-body {
min-width: unset;
max-width: unset;
width: 550px;
}
}
}

View File

@ -11,6 +11,10 @@
height: 34px; height: 34px;
min-width: 220px; min-width: 220px;
&.is-hidden {
display: none;
}
&.small { &.small {
height: 28px; height: 28px;
} }
@ -128,6 +132,18 @@
margin-left: 5px; margin-left: 5px;
pointer-events: none; pointer-events: none;
} }
.d-button-label {
display: flex;
align-items: center;
white-space: nowrap;
overflow: hidden;
.d-icon {
margin-left: 5px;
margin-right: 0;
}
}
} }
.select-box-body { .select-box-body {

View File

@ -0,0 +1,44 @@
import componentTest from 'helpers/component-test';
import Topic from 'discourse/models/topic';
const buildTopic = function() {
return Topic.create({
id: 1234,
title: "Qunit Test Topic",
deleted: false,
pinned: true
});
};
moduleForComponent('pinned-button', { integration: true });
componentTest('updating the content refreshes the list', {
template: '{{pinned-button topic=topic}}',
beforeEach() {
this.siteSettings.automatically_unpin_topics = false;
this.set("topic", buildTopic());
},
test(assert) {
andThen(() => {
assert.equal(find(".pinned-button").hasClass("is-hidden"), false);
});
click(".select-box-header");
andThen(() => {
assert.equal(find(".select-box-row.is-selected .title").html().trim(), "Pinned");
});
andThen(() => {
this.set("topic.pinned", false);
assert.equal(find(".select-box-row.is-selected .title").html().trim(), "Unpinned");
});
andThen(() => {
this.set("topic.deleted", true);
assert.equal(find(".pinned-button").hasClass("is-hidden"), true);
});
}
});

View File

@ -129,6 +129,7 @@ export default function() {
this.get("/t/28830.json", () => response(fixturesByUrl['/t/28830/1.json'])); this.get("/t/28830.json", () => response(fixturesByUrl['/t/28830/1.json']));
this.get("/t/9.json", () => response(fixturesByUrl['/t/9/1.json'])); this.get("/t/9.json", () => response(fixturesByUrl['/t/9/1.json']));
this.get("/t/12.json", () => response(fixturesByUrl['/t/12/1.json'])); this.get("/t/12.json", () => response(fixturesByUrl['/t/12/1.json']));
this.put("/t/1234/re-pin", success);
this.get("/t/id_for/:slug", () => { this.get("/t/id_for/:slug", () => {
return response({id: 280, slug: "internationalization-localization", url: "/t/internationalization-localization/280"}); return response({id: 280, slug: "internationalization-localization", url: "/t/internationalization-localization/280"});
@ -400,4 +401,4 @@ export default function() {
server.checkPassthrough = request => request.requestHeaders['Discourse-Script']; server.checkPassthrough = request => request.requestHeaders['Discourse-Script'];
return server; return server;
} }