FEATURE: make pin expiration mandatory

This commit is contained in:
Régis Hanol
2015-07-29 16:34:21 +02:00
parent 9e2632badd
commit faf4f44776
18 changed files with 192 additions and 97 deletions

View File

@@ -4,7 +4,9 @@ const icons = {
'archived.enabled': 'folder',
'archived.disabled': 'folder-open',
'pinned.enabled': 'thumb-tack',
'pinned.disabled': 'thumb-tack',
'pinned.disabled': 'thumb-tack unpinned',
'pinned_globally.enabled': 'thumb-tack',
'pinned_globally.disabled': 'thumb-tack unpinned',
'visible.enabled': 'eye',
'visible.disabled': 'eye-slash'
};

View File

@@ -10,15 +10,23 @@ export default ObjectController.extend(ModalFunctionality, {
pinnedGloballyCount: 0,
bannerCount: 0,
reset: function() {
this.set("model.pinnedInCategoryUntil", null);
this.set("model.pinnedGloballyUntil", null);
},
categoryLink: function() {
return categoryLinkHTML(this.get("model.category"), { allowUncategorized: true });
}.property("model.category"),
unPinMessage: function() {
return this.get("model.pinned_globally") ?
I18n.t("topic.feature_topic.unpin_globally") :
I18n.t("topic.feature_topic.unpin", { categoryLink: this.get("categoryLink") });
}.property("categoryLink", "model.pinned_globally"),
let name = "topic.feature_topic.unpin";
if (this.get("model.pinned_globally")) name += "_globally";
if (moment(this.get("model.pinned_until")) > moment()) name += "_until";
const until = moment(this.get("model.pinned_until")).format("LL");
return I18n.t(name, { categoryLink: this.get("categoryLink"), until: until });
}.property("categoryLink", "model.{pinned_globally,pinned_until}"),
pinMessage: function() {
return I18n.t("topic.feature_topic.pin", { categoryLink: this.get("categoryLink") });
@@ -28,6 +36,30 @@ export default ObjectController.extend(ModalFunctionality, {
return I18n.t("topic.feature_topic.already_pinned", { categoryLink: this.get("categoryLink"), count: this.get("pinnedInCategoryCount") });
}.property("categoryLink", "pinnedInCategoryCount"),
pinDisabled: function() {
return !this._isDateValid(this.get("parsedPinnedInCategoryUntil"));
}.property("parsedPinnedInCategoryUntil"),
pinGloballyDisabled: function() {
return !this._isDateValid(this.get("parsedPinnedGloballyUntil"));
}.property("pinnedGloballyUntil"),
parsedPinnedInCategoryUntil: function() {
return this._parseDate(this.get("model.pinnedInCategoryUntil"));
}.property("model.pinnedInCategoryUntil"),
parsedPinnedGloballyUntil: function() {
return this._parseDate(this.get("model.pinnedGloballyUntil"));
}.property("model.pinnedGloballyUntil"),
_parseDate(date) {
return moment(date, ["YYYY-MM-DD", "YYYY-MM-DD HH:mm"]);
},
_isDateValid(parsedDate) {
return parsedDate.isValid() && parsedDate > moment();
},
onShow() {
this.set("loading", true);

View File

@@ -99,19 +99,6 @@ export default ObjectController.extend(SelectedPostsCount, BufferedContent, {
this.set('selectedReplies', []);
}.on('init'),
_togglePinnedStates(property) {
const value = this.get('model.pinned_at') ? false : true,
topic = this.get('content');
// optimistic update
topic.setProperties({
pinned_at: value,
pinned_globally: value
});
return topic.saveStatus(property, value);
},
actions: {
deleteTopic() {
this.deleteTopic();
@@ -371,27 +358,31 @@ export default ObjectController.extend(SelectedPostsCount, BufferedContent, {
togglePinned() {
const value = this.get('model.pinned_at') ? false : true,
topic = this.get('content');
topic = this.get('content'),
until = this.get('model.pinnedInCategoryUntil');
// optimistic update
topic.setProperties({
pinned_at: value ? moment() : null,
pinned_globally: false
pinned_globally: false,
pinned_until: value ? until : null
});
return topic.saveStatus("pinned", value);
return topic.saveStatus("pinned", value, until);
},
pinGlobally() {
const topic = this.get('content');
const topic = this.get('content'),
until = this.get('model.pinnedGloballyUntil');
// optimistic update
topic.setProperties({
pinned_at: moment(),
pinned_globally: true
pinned_globally: true,
pinned_until: until
});
return topic.saveStatus("pinned_globally", true);
return topic.saveStatus("pinned_globally", true, until);
},
toggleArchived() {

View File

@@ -154,13 +154,17 @@ const Topic = RestModel.extend({
this.saveStatus(property, !!this.get(property));
},
saveStatus(property, value) {
saveStatus(property, value, until) {
if (property === 'closed' && value === true) {
this.set('details.auto_close_at', null);
}
return Discourse.ajax(this.get('url') + "/status", {
type: 'PUT',
data: { status: property, enabled: !!value }
data: {
status: property,
enabled: !!value,
until: until
}
});
},

View File

@@ -61,6 +61,7 @@ const TopicRoute = Discourse.Route.extend(ShowFooter, {
showFeatureTopic() {
showModal('featureTopic', { model: this.modelFor('topic'), title: 'topic.feature_topic.title' });
this.controllerFor('modal').set('modalClass', 'feature-topic-modal');
this.controllerFor('feature_topic').reset();
},
showInvite() {

View File

@@ -1,80 +1,94 @@
<div class="modal-body feature-topic">
{{#if model.pinned_at}}
<div class="feature-section">
<div class="button">
{{d-button action="unpin" icon="thumb-tack" label="topic.feature.unpin" class="btn-primary"}}
</div>
<div class="desc">
<p>{{{unPinMessage}}}</p>
{{#if model.pinned_globally}}
<p>{{i18n "topic.feature_topic.global_pin_note"}}</p>
<p>
{{#conditional-loading-spinner size="small" condition=loading}}
{{{i18n "topic.feature_topic.already_pinned_globally" count=pinnedGloballyCount}}}
{{/conditional-loading-spinner}}
</p>
<p>{{i18n "topic.feature_topic.global_pin_note"}}</p>
{{else}}
<p>{{i18n "topic.feature_topic.pin_note"}}</p>
<p>
{{#conditional-loading-spinner size="small" condition=loading}}
{{{alreadyPinnedMessage}}}
{{/conditional-loading-spinner}}
</p>
<p>{{i18n "topic.feature_topic.pin_note"}}</p>
{{/if}}
<p>{{{unPinMessage}}}</p>
<p>{{d-button action="unpin" icon="thumb-tack" label="topic.feature.unpin" class="btn-primary"}}</p>
</div>
</div>
{{else}}
<div class="feature-section">
<div class="button">
{{d-button action="pin" icon="thumb-tack" label="topic.feature.pin" class="btn-primary"}}
</div>
<div class="desc">
<p>{{{pinMessage}}}</p>
<p>{{i18n "topic.feature_topic.pin_note"}}</p>
<p>
{{#conditional-loading-spinner size="small" condition=loading}}
{{{alreadyPinnedMessage}}}
{{/conditional-loading-spinner}}
</p>
<p>
{{i18n "topic.feature_topic.pin_note"}}
</p>
<p>
{{{pinMessage}}}
{{fa-icon "clock-o"}}
{{input type="date" value=model.pinnedInCategoryUntil}}
</p>
<p>
{{d-button action="pin" icon="thumb-tack" label="topic.feature.pin" class="btn-primary" disabled=pinDisabled}}
</p>
</div>
</div>
<hr>
<div class="feature-section">
<div class="button">
{{d-button action="pinGlobally" icon="thumb-tack" label="topic.feature.pin_globally" class="btn-primary"}}
</div>
<div class="desc">
<p>{{i18n "topic.feature_topic.pin_globally"}}</p>
<p>{{i18n "topic.feature_topic.global_pin_note"}}</p>
<p>
{{#conditional-loading-spinner size="small" condition=loading}}
{{{i18n "topic.feature_topic.already_pinned_globally" count=pinnedGloballyCount}}}
{{/conditional-loading-spinner}}
</p>
<p>
{{i18n "topic.feature_topic.global_pin_note"}}
</p>
<p>
{{i18n "topic.feature_topic.pin_globally"}}
{{fa-icon "clock-o"}}
{{input type="date" value=model.pinnedGloballyUntil}}
</p>
<p>
{{d-button action="pinGlobally" icon="thumb-tack" label="topic.feature.pin_globally" class="btn-primary" disabled=pinGloballyDisabled}}
</p>
</div>
</div>
{{/if}}
<hr>
<div class="feature-section">
<div class="button">
{{#if model.isBanner}}
{{d-button action="removeBanner" icon="thumb-tack" label="topic.feature.remove_banner" class="btn-primary"}}
{{else}}
{{d-button action="makeBanner" icon="thumb-tack" label="topic.feature.make_banner" class="btn-primary"}}
{{/if}}
</div>
<div class="desc">
{{#if model.isBanner}}
<p>{{i18n "topic.feature_topic.remove_banner"}}</p>
{{else}}
<p>{{i18n "topic.feature_topic.make_banner"}}</p>
{{/if}}
<p>{{i18n "topic.feature_topic.banner_note"}}</p>
<p>
{{#conditional-loading-spinner size="small" condition=loading}}
{{{i18n "topic.feature_topic.already_banner" count=bannerCount}}}
{{/conditional-loading-spinner}}
</p>
<p>
{{i18n "topic.feature_topic.banner_note"}}
</p>
<p>
{{#if model.isBanner}}
{{i18n "topic.feature_topic.remove_banner"}}
{{else}}
{{i18n "topic.feature_topic.make_banner"}}
{{/if}}
</p>
<p>
{{#if model.isBanner}}
{{d-button action="removeBanner" icon="thumb-tack" label="topic.feature.remove_banner" class="btn-primary"}}
{{else}}
{{d-button action="makeBanner" icon="thumb-tack" label="topic.feature.make_banner" class="btn-primary"}}
{{/if}}
</p>
</div>
</div>
</div>

View File

@@ -30,30 +30,36 @@
}
}
.modal-body.feature-topic .feature-section {
display: block;
.button {
width: 33%;
display: inline-block;
vertical-align: top;
margin-top: 15px;
.modal-body.feature-topic {
padding: 5px;
max-height: 500px;
hr {
margin: 10px 0;
}
.desc {
display: inline-block;
vertical-align: middle;
max-width: 60%;
margin-left: 10px;
p {
margin: 10px 0;
.feature-section {
display: block;
.badge-wrapper {
margin-right: 0;
}
input[type="date"] {
width: 120px;
margin: 0;
}
.desc {
display: inline-block;
vertical-align: middle;
margin-left: 10px;
p:first-of-type {
margin: 0;
}
p {
margin: 10px 0 0;
}
}
}
}
.mobile-view .feature-topic .feature-section {
.button {
width: auto;
display: block;
margin: 0 10px;
}
.desc {
display: block;
clear: both;