mirror of
https://github.com/discourse/discourse.git
synced 2025-02-25 18:55:32 -06:00
FEATURE: make pin expiration mandatory
This commit is contained in:
@@ -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'
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user