Merge branch 'master' of github.com:discourse/discourse
This commit is contained in:
commit
fe8d9642a0
|
@ -1,43 +0,0 @@
|
|||
import { daysSinceEpoch } from "discourse/helpers/cold-age-class";
|
||||
|
||||
export default Ember.Component.extend({
|
||||
tagName: 'td',
|
||||
classNameBindings: [':activity', 'coldness'],
|
||||
attributeBindings: ['title'],
|
||||
|
||||
// returns createdAt if there's no bumped date
|
||||
bumpedAt: function() {
|
||||
var bumpedAt = this.get('topic.bumped_at');
|
||||
if (bumpedAt) {
|
||||
return new Date(bumpedAt);
|
||||
} else {
|
||||
return this.get('createdAt');
|
||||
}
|
||||
}.property('topic.bumped_at', 'createdAt'),
|
||||
|
||||
createdAt: function() {
|
||||
return new Date(this.get('topic.created_at'));
|
||||
}.property('topic.created_at'),
|
||||
|
||||
coldness: function() {
|
||||
var bumpedAt = this.get('bumpedAt'),
|
||||
createdAt = this.get('createdAt');
|
||||
|
||||
if (!bumpedAt) { return; }
|
||||
var delta = daysSinceEpoch(bumpedAt) - daysSinceEpoch(createdAt);
|
||||
|
||||
if (delta > Discourse.SiteSettings.cold_age_days_high) { return 'coldmap-high'; }
|
||||
if (delta > Discourse.SiteSettings.cold_age_days_medium) { return 'coldmap-med'; }
|
||||
if (delta > Discourse.SiteSettings.cold_age_days_low) { return 'coldmap-low'; }
|
||||
}.property('bumpedAt', 'createdAt'),
|
||||
|
||||
title: function() {
|
||||
return I18n.t('first_post') + ": " + Discourse.Formatter.longDate(this.get('createdAt')) + "\n" +
|
||||
I18n.t('last_post') + ": " + Discourse.Formatter.longDate(this.get('bumpedAt'));
|
||||
}.property('bumpedAt', 'createdAt'),
|
||||
|
||||
render: function(buffer) {
|
||||
buffer.push("<a href='" + this.get('topic.lastPostUrl') +"'>" + Discourse.Formatter.autoUpdatingRelativeAge(this.get('bumpedAt')) + "</a>");
|
||||
}
|
||||
|
||||
});
|
|
@ -57,6 +57,16 @@ export default Ember.Component.extend({
|
|||
|
||||
actions: {
|
||||
expand: function() {
|
||||
var self = this;
|
||||
|
||||
if(!this.get('renderCategories')){
|
||||
this.set('renderCategories',true);
|
||||
Em.run.next(function(){
|
||||
self.send('expand');
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.get('expanded')) {
|
||||
this.close();
|
||||
return;
|
||||
|
@ -65,8 +75,7 @@ export default Ember.Component.extend({
|
|||
if (this.get('categories')) {
|
||||
this.set('expanded', true);
|
||||
}
|
||||
var self = this,
|
||||
$dropdown = this.$()[0];
|
||||
var $dropdown = this.$()[0];
|
||||
|
||||
this.$('a[data-drop-close]').on('click.category-drop', function() {
|
||||
self.close();
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
export default Ember.Component.extend({
|
||||
import VisibleComponent from "discourse/components/visible";
|
||||
|
||||
export default VisibleComponent.extend({
|
||||
|
||||
visible: function () {
|
||||
var bannerKey = this.get("banner.key"),
|
||||
|
@ -20,6 +22,7 @@ export default Ember.Component.extend({
|
|||
Discourse.KeyValueStore.set({ key: "dismissed_banner_key", value: this.get("banner.key") });
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
});
|
||||
|
|
|
@ -43,7 +43,7 @@ export default Ember.Component.extend({
|
|||
|
||||
this.sendAction('action', {
|
||||
topic: topic,
|
||||
position: this.$('a').position()
|
||||
position: this.$('a').offset()
|
||||
});
|
||||
|
||||
return false;
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
export default Ember.Component.extend({
|
||||
visibleChanged: function(){
|
||||
this.rerender();
|
||||
}.observes("visible"),
|
||||
|
||||
render: function(buffer){
|
||||
if(!this.get("visible")){
|
||||
return;
|
||||
}
|
||||
|
||||
return this._super(buffer);
|
||||
}
|
||||
});
|
|
@ -121,7 +121,6 @@ var controllerOpts = {
|
|||
|
||||
canBulkSelect: Em.computed.alias('currentUser.staff'),
|
||||
hasTopics: Em.computed.gt('topics.length', 0),
|
||||
showTable: Em.computed.or('hasTopics', 'topicTrackingState.hasIncoming'),
|
||||
allLoaded: Em.computed.empty('more_topics_url'),
|
||||
latest: Discourse.computed.endWith('filter', 'latest'),
|
||||
new: Discourse.computed.endWith('filter', 'new'),
|
||||
|
|
|
@ -53,8 +53,8 @@ export default ObjectController.extend(ModalFunctionality, {
|
|||
displayGoToNext: function() { return this.get("next_revision") && this.get("current_revision") < this.get("next_revision"); }.property("current_revision", "next_revision"),
|
||||
displayGoToLast: function() { return this.get("current_revision") < this.get("last_revision"); }.property("current_revision", "last_revision"),
|
||||
|
||||
displayShow: function() { return !Discourse.Mobile.mobileView && this.get("previous_hidden") && Discourse.User.currentProp('staff'); }.property("previous_hidden"),
|
||||
displayHide: function() { return !Discourse.Mobile.mobileView && !this.get("previous_hidden") && Discourse.User.currentProp('staff'); }.property("previous_hidden"),
|
||||
displayShow: function() { return this.get("previous_hidden") && Discourse.User.currentProp('staff') && !this.get("loading"); }.property("previous_hidden", "loading"),
|
||||
displayHide: function() { return !this.get("previous_hidden") && Discourse.User.currentProp('staff') && !this.get("loading"); }.property("previous_hidden", "loading"),
|
||||
|
||||
isEitherRevisionHidden: Em.computed.or("previous_hidden", "current_hidden"),
|
||||
|
||||
|
|
|
@ -8,18 +8,25 @@ export function daysSinceEpoch(dt) {
|
|||
**/
|
||||
function coldAgeClass(property, options) {
|
||||
var dt = Em.Handlebars.get(this, property, options);
|
||||
var className = (options && options.hash && options.hash.class !== undefined) ? options.hash.class : 'age';
|
||||
|
||||
if (!dt) { return 'age'; }
|
||||
if (!dt) { return className; }
|
||||
|
||||
var startDate = (options && options.hash && options.hash.startDate) || new Date();
|
||||
|
||||
if (typeof startDate === "string") {
|
||||
startDate = Em.Handlebars.get(this, startDate, options);
|
||||
}
|
||||
|
||||
// Show heat on age
|
||||
var nowDays = daysSinceEpoch(new Date()),
|
||||
var nowDays = daysSinceEpoch(startDate),
|
||||
epochDays = daysSinceEpoch(new Date(dt));
|
||||
|
||||
if (nowDays - epochDays > Discourse.SiteSettings.cold_age_days_high) return 'age coldmap-high';
|
||||
if (nowDays - epochDays > Discourse.SiteSettings.cold_age_days_medium) return 'age coldmap-med';
|
||||
if (nowDays - epochDays > Discourse.SiteSettings.cold_age_days_low) return 'age coldmap-low';
|
||||
if (nowDays - epochDays > Discourse.SiteSettings.cold_age_days_high) return className + ' coldmap-high';
|
||||
if (nowDays - epochDays > Discourse.SiteSettings.cold_age_days_medium) return className + ' coldmap-med';
|
||||
if (nowDays - epochDays > Discourse.SiteSettings.cold_age_days_low) return className + ' coldmap-low';
|
||||
|
||||
return 'age';
|
||||
return className;
|
||||
}
|
||||
|
||||
Handlebars.registerHelper('cold-age-class', coldAgeClass);
|
||||
|
|
|
@ -3,19 +3,27 @@
|
|||
update the dates on a regular interval.
|
||||
**/
|
||||
Handlebars.registerHelper('format-date', function(property, options) {
|
||||
var leaveAgo;
|
||||
if (property.hash) {
|
||||
if (property.hash.leaveAgo) {
|
||||
leaveAgo = property.hash.leaveAgo === "true";
|
||||
var leaveAgo, format = 'medium', title = true;
|
||||
var hash = property.hash || (options && options.hash);
|
||||
|
||||
if (hash) {
|
||||
if (hash.leaveAgo) {
|
||||
leaveAgo = hash.leaveAgo === "true";
|
||||
}
|
||||
if (property.hash.path) {
|
||||
property = property.hash.path;
|
||||
if (hash.path) {
|
||||
property = hash.path;
|
||||
}
|
||||
if (hash.format) {
|
||||
format = hash.format;
|
||||
}
|
||||
if (hash.noTitle) {
|
||||
title = false;
|
||||
}
|
||||
}
|
||||
|
||||
var val = Ember.Handlebars.get(this, property, options);
|
||||
if (val) {
|
||||
var date = new Date(val);
|
||||
return new Handlebars.SafeString(Discourse.Formatter.autoUpdatingRelativeAge(date, {format: 'medium', title: true, leaveAgo: leaveAgo}));
|
||||
return new Handlebars.SafeString(Discourse.Formatter.autoUpdatingRelativeAge(date, {format: format, title: title, leaveAgo: leaveAgo}));
|
||||
}
|
||||
});
|
||||
|
|
|
@ -23,7 +23,7 @@ I18n.toHumanSize = function(number, options) {
|
|||
@method i18n
|
||||
@for Handlebars
|
||||
**/
|
||||
Ember.Handlebars.registerHelper('i18n', function(property, options) {
|
||||
Handlebars.registerHelper('i18n', function(property, options) {
|
||||
// Resolve any properties
|
||||
var params = options.hash,
|
||||
self = this;
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
Handlebars.registerHelper('raw', function(property, options) {
|
||||
|
||||
var template = Em.TEMPLATES[property + ".raw"];
|
||||
var params = options.hash;
|
||||
|
||||
if(params) {
|
||||
for(var prop in params){
|
||||
if(options.hashTypes[prop] === "ID") {
|
||||
params[prop] = Em.Handlebars.get(this, params[prop], options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new Handlebars.SafeString(template(params));
|
||||
});
|
|
@ -0,0 +1,101 @@
|
|||
// keep IIF for simpler testing
|
||||
|
||||
// EmberCompatHandlebars is a mechanism for quickly rendering templates which is Ember aware
|
||||
// templates are highly compatible with Ember so you don't need to worry about calling "get"
|
||||
// and computed properties function, additionally it uses stringParams like Ember does
|
||||
|
||||
(function(){
|
||||
|
||||
// compat with ie8 in case this gets picked up elsewhere
|
||||
var objectCreate = Object.create || function(parent) {
|
||||
function F() {}
|
||||
F.prototype = parent;
|
||||
return new F();
|
||||
};
|
||||
|
||||
|
||||
var RawHandlebars = objectCreate(Handlebars);
|
||||
|
||||
RawHandlebars.helper = function() {};
|
||||
RawHandlebars.helpers = objectCreate(Handlebars.helpers);
|
||||
|
||||
RawHandlebars.helpers.get = function(context, options){
|
||||
var firstContext = options.contexts[0];
|
||||
var val = firstContext[context];
|
||||
val = val === undefined ? Em.get(firstContext, context): val;
|
||||
return val;
|
||||
};
|
||||
|
||||
// adds compatability so this works with stringParams
|
||||
var stringCompatHelper = function(fn){
|
||||
|
||||
var old = RawHandlebars.helpers[fn];
|
||||
RawHandlebars.helpers[fn] = function(context,options){
|
||||
return old.apply(this, [
|
||||
RawHandlebars.helpers.get(context,options),
|
||||
options
|
||||
]);
|
||||
};
|
||||
};
|
||||
|
||||
stringCompatHelper("each");
|
||||
stringCompatHelper("if");
|
||||
stringCompatHelper("unless");
|
||||
stringCompatHelper("with");
|
||||
|
||||
|
||||
RawHandlebars.Compiler = function() {};
|
||||
RawHandlebars.Compiler.prototype = objectCreate(Handlebars.Compiler.prototype);
|
||||
RawHandlebars.Compiler.prototype.compiler = RawHandlebars.Compiler;
|
||||
|
||||
RawHandlebars.JavaScriptCompiler = function() {};
|
||||
|
||||
RawHandlebars.JavaScriptCompiler.prototype = objectCreate(Handlebars.JavaScriptCompiler.prototype);
|
||||
RawHandlebars.JavaScriptCompiler.prototype.compiler = RawHandlebars.JavaScriptCompiler;
|
||||
RawHandlebars.JavaScriptCompiler.prototype.namespace = "Discourse.EmberCompatHandlebars";
|
||||
|
||||
|
||||
RawHandlebars.Compiler.prototype.mustache = function(mustache) {
|
||||
if ( !(mustache.params.length || mustache.hash)) {
|
||||
|
||||
var id = new Handlebars.AST.IdNode([{ part: 'get' }]);
|
||||
|
||||
mustache = new Handlebars.AST.MustacheNode([id].concat([mustache.id]), mustache.hash, mustache.escaped);
|
||||
}
|
||||
|
||||
return Handlebars.Compiler.prototype.mustache.call(this, mustache);
|
||||
};
|
||||
|
||||
RawHandlebars.precompile = function(value, asObject) {
|
||||
var ast = Handlebars.parse(value);
|
||||
|
||||
var options = {
|
||||
knownHelpers: {
|
||||
get: true
|
||||
},
|
||||
data: true,
|
||||
stringParams: true
|
||||
};
|
||||
|
||||
asObject = asObject === undefined ? true : asObject;
|
||||
|
||||
var environment = new RawHandlebars.Compiler().compile(ast, options);
|
||||
return new RawHandlebars.JavaScriptCompiler().compile(environment, options, undefined, asObject);
|
||||
};
|
||||
|
||||
|
||||
RawHandlebars.compile = function(string) {
|
||||
var ast = Handlebars.parse(string);
|
||||
// this forces us to rewrite helpers
|
||||
var options = { data: true, stringParams: true };
|
||||
var environment = new RawHandlebars.Compiler().compile(ast, options);
|
||||
var templateSpec = new RawHandlebars.JavaScriptCompiler().compile(environment, options, undefined, true);
|
||||
|
||||
var template = RawHandlebars.template(templateSpec);
|
||||
|
||||
return template;
|
||||
};
|
||||
|
||||
Discourse.EmberCompatHandlebars = RawHandlebars;
|
||||
|
||||
})();
|
|
@ -1,5 +1,24 @@
|
|||
Discourse.Topic = Discourse.Model.extend({
|
||||
|
||||
// returns createdAt if there's no bumped date
|
||||
bumpedAt: function() {
|
||||
var bumpedAt = this.get('bumped_at');
|
||||
if (bumpedAt) {
|
||||
return new Date(bumpedAt);
|
||||
} else {
|
||||
return this.get('createdAt');
|
||||
}
|
||||
}.property('bumped_at', 'createdAt'),
|
||||
|
||||
bumpedAtTitle: function() {
|
||||
return I18n.t('first_post') + ": " + Discourse.Formatter.longDate(this.get('createdAt')) + "\n" +
|
||||
I18n.t('last_post') + ": " + Discourse.Formatter.longDate(this.get('bumpedAt'));
|
||||
}.property('bumpedAt'),
|
||||
|
||||
createdAt: function() {
|
||||
return new Date(this.get('created_at'));
|
||||
}.property('created_at'),
|
||||
|
||||
postStream: function() {
|
||||
return Discourse.PostStream.create({topic: this});
|
||||
}.property(),
|
||||
|
|
|
@ -28,11 +28,7 @@
|
|||
url=topic.lastUnreadUrl}}
|
||||
</td>
|
||||
|
||||
{{#unless controller.hideCategory}}
|
||||
<td class="category">
|
||||
{{category-link topic.category showParent=true}}
|
||||
</td>
|
||||
{{/unless}}
|
||||
{{raw "list/category_column" hideCategory=controller.hideCategory category=topic.category}}
|
||||
|
||||
{{posts-count-column topic=topic class="num" action="clickedPosts"}}
|
||||
|
||||
|
@ -48,7 +44,7 @@
|
|||
{{number topic.views numberKey="views_long"}}
|
||||
</td>
|
||||
|
||||
{{activity-column topic=topic class="num"}}
|
||||
{{raw "list/activity_column" topic=topic class="num" tagName="td"}}
|
||||
</tr>
|
||||
{{/grouped-each}}
|
||||
</tbody>
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
{{#if subCategory}}
|
||||
<div class='cat'><a {{bind-attr href=noCategoriesUrl}} data-drop-close="true" class='badge-category home'>{{i18n categories.no_subcategory}}</a></div>
|
||||
{{/if}}
|
||||
{{#if renderCategories}}
|
||||
{{#each categories}}<div class='cat'>{{category-link this allowUncategorized=true}}</div>{{/each}}
|
||||
{{/if}}
|
||||
</section>
|
||||
{{/if}}
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
{{#if visible}}
|
||||
<div class="row">
|
||||
<div id="banner" {{bind-attr class="overlay"}}>
|
||||
<div id="banner-content">
|
||||
<div class="close" {{action "dismiss"}}><i class="fa fa-times" title="{{i18n banner.close}}"></i></div>
|
||||
{{{banner.html}}}
|
||||
</div>
|
||||
<div class="row">
|
||||
<div id="banner" {{bind-attr class="overlay"}}>
|
||||
<div id="banner-content">
|
||||
<div class="close" {{action "dismiss"}}><i class="fa fa-times" title="{{i18n banner.close}}"></i></div>
|
||||
{{{banner.html}}}
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
|
|
@ -26,53 +26,46 @@
|
|||
{{top-period-chooser period=period}}
|
||||
</div>
|
||||
{{/if}}
|
||||
{{#if showTable}}
|
||||
{{#if topicTrackingState.hasIncoming}}
|
||||
<div class="show-more">
|
||||
<div class='alert alert-info clickable' {{action "showInserted"}}>
|
||||
{{countI18n topic_count_ suffix=topicTrackingState.filter count=topicTrackingState.incomingCount}}
|
||||
{{i18n click_to_show}}
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{#if hasTopics}}
|
||||
<table class='topic-list'>
|
||||
<thead>
|
||||
<tr>
|
||||
{{#if currentUser}}
|
||||
<th class='star'>
|
||||
{{#if canBulkSelect}}
|
||||
<button class='btn bulk-select' {{action "toggleBulkSelect"}} title="{{i18n topics.bulk.toggle}}"><i class='fa fa-list'></i></button>
|
||||
<tr>
|
||||
{{#if currentUser}}
|
||||
<th class='star'>
|
||||
{{#if canBulkSelect}}
|
||||
<button class='btn bulk-select' {{action "toggleBulkSelect"}} title="{{i18n topics.bulk.toggle}}"><i class='fa fa-list'></i></button>
|
||||
{{/if}}
|
||||
</th>
|
||||
{{/if}}
|
||||
</th>
|
||||
{{/if}}
|
||||
{{#sortable-heading class="default"}} {{i18n topic.title}} {{/sortable-heading}}
|
||||
{{#unless controller.hideCategory}}
|
||||
{{#sortable-heading sortBy="category" action="changeSort" order=order ascending=ascending}}
|
||||
{{i18n category_title}}
|
||||
{{#sortable-heading class="default"}} {{i18n topic.title}} {{/sortable-heading}}
|
||||
{{#unless controller.hideCategory}}
|
||||
{{#sortable-heading sortBy="category" action="changeSort" order=order ascending=ascending}}
|
||||
{{i18n category_title}}
|
||||
{{/sortable-heading}}
|
||||
{{/unless}}
|
||||
{{#sortable-heading class="posters"}} {{i18n users}} {{/sortable-heading}}
|
||||
{{#sortable-heading sortBy="posts" number=true action="changeSort" order=order ascending=ascending}}
|
||||
{{i18n posts}}
|
||||
{{/sortable-heading}}
|
||||
{{/unless}}
|
||||
{{#sortable-heading class="posters"}} {{i18n users}} {{/sortable-heading}}
|
||||
{{#sortable-heading sortBy="posts" number=true action="changeSort" order=order ascending=ascending}}
|
||||
{{i18n posts}}
|
||||
{{/sortable-heading}}
|
||||
{{#sortable-heading sortBy="views" number=true action="changeSort" order=order ascending=ascending}}
|
||||
{{i18n views}}
|
||||
{{/sortable-heading}}
|
||||
{{#sortable-heading sortBy="activity" number=true action="changeSort" order=order ascending=ascending}}
|
||||
{{i18n activity}}
|
||||
{{/sortable-heading}}
|
||||
</tr>
|
||||
{{#sortable-heading sortBy="views" number=true action="changeSort" order=order ascending=ascending}}
|
||||
{{i18n views}}
|
||||
{{/sortable-heading}}
|
||||
{{#sortable-heading sortBy="activity" number=true action="changeSort" order=order ascending=ascending}}
|
||||
{{i18n activity}}
|
||||
{{/sortable-heading}}
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
{{#if topicTrackingState.hasIncoming}}
|
||||
<tbody>
|
||||
<tr>
|
||||
<td colspan="9">
|
||||
<div class='alert alert-info clickable' {{action "showInserted"}}>
|
||||
{{countI18n topic_count_ suffix=topicTrackingState.filter count=topicTrackingState.incomingCount}}
|
||||
{{i18n click_to_show}}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
{{/if}}
|
||||
|
||||
<tbody>
|
||||
{{each topics itemController="topic-list-item" itemView="topic-list-item"}}
|
||||
</tbody>
|
||||
|
||||
</table>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
|
|
@ -80,16 +80,20 @@
|
|||
{{/if}}
|
||||
</ul>
|
||||
|
||||
{{render "search"}}
|
||||
{{#if view.renderDropdowns}}
|
||||
|
||||
{{render "notifications" notifications}}
|
||||
{{render "search"}}
|
||||
|
||||
{{render "notifications" notifications}}
|
||||
|
||||
{{#if view.renderSiteMap}}
|
||||
{{render "siteMap"}}
|
||||
{{/if}}
|
||||
|
||||
{{render "user-dropdown"}}
|
||||
|
||||
{{#if view.renderSiteMap}}
|
||||
{{render "siteMap"}}
|
||||
{{/if}}
|
||||
|
||||
{{render "user-dropdown"}}
|
||||
|
||||
</div>
|
||||
|
||||
{{#if showExtraInfo}}
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
<{{this.tagName}} class="{{class}} {{cold-age-class topic.createdAt startDate=topic.bumpedAt class=""}} activity" title="{{topic.bumpedAtTitle}}"><a href="{{topic.lastPostUrl}}">{{format-date topic.bumpedAt format="tiny" noTitle=true}}</a></{{this.tagName}}>
|
|
@ -0,0 +1,3 @@
|
|||
{{#unless hideCategory}}
|
||||
<td class='category'>{{category-link category showParent=true}}</td>
|
||||
{{/unless}}
|
|
@ -0,0 +1,5 @@
|
|||
<td class='posters'>
|
||||
{{#each posters}}
|
||||
<a href="{{user.path}}" data-user-card="{{user.username}}" class="{{extras}}">{{avatar this usernamePath="user.username" imageSize="small"}}</a>
|
||||
{{/each}}
|
||||
</td>
|
|
@ -0,0 +1,8 @@
|
|||
{{#if topic.hasExcerpt}}
|
||||
<div class="topic-excerpt">
|
||||
{{{topic.excerpt}}}
|
||||
{{#if topic.excerptTruncated}}
|
||||
<a href="{{topic.url}}">{{i18n read_more}}</a>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
|
@ -10,30 +10,20 @@
|
|||
{{/if}}
|
||||
{{/if}}
|
||||
|
||||
<td class='main-link clearfix' {{bind-attr colspan="titleColSpan"}}>
|
||||
<td class='main-link clearfix' colspan="{{unbound titleColSpan}}">
|
||||
{{topic-status topic=this.model}}
|
||||
{{topic-link this}}
|
||||
{{#if showTopicPostBadges}}
|
||||
{{topic-post-badges unread=unread newPosts=displayNewPosts unseen=unseen url=lastUnreadUrl}}
|
||||
{{/if}}
|
||||
|
||||
{{#if hasExcerpt}}
|
||||
<div class="topic-excerpt">
|
||||
{{{excerpt}}}
|
||||
{{#if excerptTruncated}}
|
||||
<a href="{{url}}">{{i18n read_more}}</a>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
||||
{{raw "list/topic_excerpt" topic=model}}
|
||||
</td>
|
||||
|
||||
{{#unless hideCategory}}
|
||||
<td class='category'>{{bound-category-link category showParent=true}}</td>
|
||||
{{/unless}}
|
||||
|
||||
{{view 'posters-column' posters=posters}}
|
||||
{{raw "list/category_column" hideCategory=hideCategory category=category}}
|
||||
{{raw "list/posters_column" posters=posters}}
|
||||
|
||||
{{posts-count-column topic=model class="num" action="showTopicEntrance"}}
|
||||
<td {{bind-attr class=":num :views viewsHeat"}}>{{number views numberKey="views_long"}}</td>
|
||||
<td class="num views {{unbound viewsHeat}}">{{number views numberKey="views_long"}}</td>
|
||||
|
||||
{{activity-column topic=model class="num"}}
|
||||
{{raw "list/activity_column" topic=model class="num" tagName="td"}}
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
<div class="topic-item-stats clearfix">
|
||||
<div class="pull-right">
|
||||
{{posts-count-column topic=topic tagName="div" class="num posts" action="clickedPosts"}}
|
||||
{{activity-column topic=topic tagName="div" class="num activity last"}}
|
||||
{{raw "list/activity_column" topic=topic tagName="div" class="num activity last"}}
|
||||
</div>
|
||||
{{#unless controller.hideCategory}}
|
||||
<div class='category'>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
{{top-period-chooser period=period}}
|
||||
</div>
|
||||
{{/if}}
|
||||
{{#if showTable}}
|
||||
{{#if hasTopics}}
|
||||
<table class='topic-list'>
|
||||
{{#if topicTrackingState.hasIncoming}}
|
||||
<tbody>
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
{{posts-count-column topic=this tagName="div" class="num posts" action="showTopicEntrance"}}
|
||||
<div class='num activity last'>
|
||||
<a href="{{lastPostUrl}}" title='{{i18n last_post}}: {{{raw-date bumped_at}}}'>{{last_poster_username}}</a>
|
||||
{{activity-column topic=this tagName="span" class="age"}}
|
||||
{{raw "list/activity_column" topic=this tagName="span" class="age"}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
|
|
|
@ -14,16 +14,26 @@ export default Discourse.View.extend({
|
|||
classNames: ['d-header', 'clearfix'],
|
||||
classNameBindings: ['editingTopic'],
|
||||
templateName: 'header',
|
||||
renderDropdowns: false,
|
||||
|
||||
showDropdown: function($target) {
|
||||
var self = this;
|
||||
|
||||
if(!this.get("renderDropdowns")){
|
||||
this.set("renderDropdowns", true);
|
||||
Em.run.next(function(){
|
||||
self.showDropdown($target);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
var elementId = $target.data('dropdown') || $target.data('notifications'),
|
||||
$dropdown = $("#" + elementId),
|
||||
$li = $target.closest('li'),
|
||||
$ul = $target.closest('ul'),
|
||||
$html = $('html'),
|
||||
$header = $('header'),
|
||||
replyZIndex = parseInt($('#reply-control').css('z-index'), 10),
|
||||
self = this;
|
||||
replyZIndex = parseInt($('#reply-control').css('z-index'), 10);
|
||||
|
||||
|
||||
originalZIndex = originalZIndex || $('header').css('z-index');
|
||||
|
|
|
@ -131,7 +131,9 @@ Discourse.PostView = Discourse.GroupedView.extend(Ember.Evented, {
|
|||
topicId = parseInt(topicId, 10);
|
||||
|
||||
Discourse.ajax("/posts/by_number/" + topicId + "/" + postId).then(function (result) {
|
||||
var parsed = $(result.cooked);
|
||||
// slightly double escape the cooked html to prevent jQuery from unescaping it
|
||||
var escaped = result.cooked.replace("&", "&");
|
||||
var parsed = $(escaped);
|
||||
parsed.replaceText(originalText, "<span class='highlighted'>" + originalText + "</span>");
|
||||
$blockQuote.showHtml(parsed, 'fast', finished);
|
||||
});
|
||||
|
|
|
@ -5,9 +5,13 @@
|
|||
// Pagedown customizations
|
||||
//= require ./pagedown_custom.js
|
||||
|
||||
// This is a BUG we should fix
|
||||
// it is only required here cause preview is not loading it using LAB
|
||||
//= require highlight.pack.js
|
||||
//
|
||||
|
||||
// Stuff we need to load first
|
||||
//= require ./discourse/lib/ember_compat_handlebars
|
||||
//= require ./discourse/lib/computed
|
||||
//= require ./discourse/mixins/scrolling
|
||||
//= require_tree ./discourse/mixins
|
||||
|
@ -38,6 +42,7 @@
|
|||
//= require ./discourse/routes/discourse_restricted_user_route
|
||||
//= require ./discourse/components/top-title
|
||||
//= require ./discourse/components/text-field
|
||||
//= require ./discourse/components/visible
|
||||
//= require ./discourse/helpers/user-avatar
|
||||
//= require ./discourse/helpers/cold-age-class
|
||||
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
.show-more {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.list-controls {
|
||||
#navigation-bar {
|
||||
.has-icon span:before {
|
||||
|
|
|
@ -2,6 +2,9 @@
|
|||
@extend .clearfix;
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
.contents {
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
|
||||
.full-width {
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
.modal.history-modal {
|
||||
#revision-numbers {
|
||||
display: inline-block;
|
||||
min-width: 100px;
|
||||
min-width: 96px;
|
||||
text-align: center;
|
||||
}
|
||||
#revision-loading {
|
||||
|
|
|
@ -117,14 +117,12 @@
|
|||
}
|
||||
|
||||
.user-main {
|
||||
|
||||
width: 100%;
|
||||
float: left;
|
||||
margin-bottom: 50px;
|
||||
|
||||
|
||||
table.group-members {
|
||||
width: 100%;
|
||||
width: 75%;
|
||||
float: right;
|
||||
|
||||
p {
|
||||
max-width: 600px;
|
||||
white-space: nowrap;
|
||||
|
@ -191,6 +189,13 @@
|
|||
overflow: hidden;
|
||||
color: $secondary;
|
||||
|
||||
&.group {
|
||||
width: 75%;
|
||||
float: right;
|
||||
margin-top: 20px;
|
||||
.details {padding: 15px;}
|
||||
}
|
||||
|
||||
.secondary {
|
||||
background: dark-light-diff($primary, $secondary, 90%, -65%);
|
||||
font-size: 13px;
|
||||
|
|
|
@ -94,7 +94,7 @@ class UsersController < ApplicationController
|
|||
end
|
||||
|
||||
def check_emails
|
||||
user = fetch_user_from_params
|
||||
user = fetch_user_from_params(include_inactive: true)
|
||||
guardian.ensure_can_check_emails!(user)
|
||||
|
||||
StaffActionLogger.new(current_user).log_check_email(user, context: params[:context])
|
||||
|
|
|
@ -96,7 +96,7 @@ Note that pinning topics works a little differently in Discourse:
|
|||
|
||||
If a pin isn't visible enough, you can also turn one single topic into a **banner**. The banner topic floats on top of all topics and all primary pages. Users can permanently dismiss this floating banner by clicking the × in the upper right corner.
|
||||
|
||||
To make (or remove) a pin or a banner, use the admin wrench at the top right of the topic.
|
||||
To make (or remove) a pin or a banner, use the admin wrench at the top right or bottom of the topic.
|
||||
|
||||
### Set the Homepage
|
||||
|
||||
|
|
|
@ -7,4 +7,4 @@ The first paragraph of this pinned topic will be visible as a welcome message to
|
|||
- Why should they come here?
|
||||
- Where can they read more (links, resources, etc)?
|
||||
|
||||
You may want to close this topic via the wrench icon at the upper right, so that replies don't pile up on an announcement.
|
||||
You may want to close this topic via the admin wrench (at the upper right and bottom), so that replies don't pile up on an announcement.
|
|
@ -155,7 +155,7 @@ module Email
|
|||
|
||||
def strip_avatars_and_emojis
|
||||
@fragment.css('img').each do |img|
|
||||
if img['src'] =~ /user_avatar/
|
||||
if img['src'] =~ /_avatar/
|
||||
img.parent['style'] = "vertical-align: top;" if img.parent.name == 'td'
|
||||
img.remove
|
||||
end
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
# barber patches to re-route raw compilation via ember compat handlebars
|
||||
#
|
||||
|
||||
module Barber
|
||||
class EmberCompatPrecompiler < Barber::Precompiler
|
||||
|
||||
def self.call(template)
|
||||
"Handlebars.template(#{compile(template)})"
|
||||
end
|
||||
|
||||
def sources
|
||||
[handlebars, precompiler]
|
||||
end
|
||||
|
||||
def precompiler
|
||||
@precompiler ||= StringIO.new <<END
|
||||
var Discourse = {};
|
||||
#{File.read(Rails.root + "app/assets/javascripts/discourse/lib/ember_compat_handlebars.js")}
|
||||
var Barber = {
|
||||
precompile: function(string) {
|
||||
return Discourse.EmberCompatHandlebars.precompile(string).toString();
|
||||
}
|
||||
};
|
||||
END
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class Ember::Handlebars::Template
|
||||
def precompile_handlebars(string)
|
||||
"Discourse.EmberCompatHandlebars.template(#{Barber::EmberCompatPrecompiler.compile(string)});"
|
||||
end
|
||||
def compile_handlebars(string)
|
||||
"Discourse.EmberCompatHandlebars.compile(#{indent(string).inspect});"
|
||||
end
|
||||
end
|
|
@ -82,7 +82,7 @@ class ImportScripts::Vanilla < ImportScripts::Base
|
|||
admin_role_id = @roles.select { |r| r[:name] == "Administrator" }.first[:role_id]
|
||||
moderator_role_id = @roles.select { |r| r[:name] == "Moderator" }.first[:role_id]
|
||||
|
||||
activities = @activities.reject { |a| a[:activity_user_id] != a[:regarding_user_id] }
|
||||
activities = (@activities || []).reject { |a| a[:activity_user_id] != a[:regarding_user_id] }
|
||||
|
||||
create_users(@users) do |user|
|
||||
next if user[:name] == "[Deleted User]"
|
||||
|
|
|
@ -521,7 +521,7 @@ describe UsersController do
|
|||
xhr :post, :create, create_params
|
||||
json = JSON::parse(response.body)
|
||||
json["success"].should_not == true
|
||||
|
||||
|
||||
# should not change the session
|
||||
session["user_created_email"].should be_blank
|
||||
end
|
||||
|
@ -1411,6 +1411,16 @@ describe UsersController do
|
|||
json["associated_accounts"].should be_present
|
||||
end
|
||||
|
||||
it "works on inactive users" do
|
||||
inactive_user = Fabricate(:user, active: false)
|
||||
Guardian.any_instance.expects(:can_check_emails?).returns(true)
|
||||
xhr :put, :check_emails, username: inactive_user.username
|
||||
response.should be_success
|
||||
json = JSON.parse(response.body)
|
||||
json["email"].should be_present
|
||||
json["associated_accounts"].should be_present
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue