diff --git a/app/assets/javascripts/discourse/components/actions-summary.js.es6 b/app/assets/javascripts/discourse/components/actions-summary.js.es6
new file mode 100644
index 00000000000..e78e7dde35a
--- /dev/null
+++ b/app/assets/javascripts/discourse/components/actions-summary.js.es6
@@ -0,0 +1,63 @@
+import StringBuffer from 'discourse/mixins/string-buffer';
+import { iconHTML } from 'discourse/helpers/fa-icon';
+
+export default Ember.Component.extend(StringBuffer, {
+ tagName: 'section',
+ classNameBindings: [':post-actions', 'hidden'],
+ actionsSummary: Em.computed.alias('post.actionsWithoutLikes'),
+ emptySummary: Em.computed.empty('actionsSummary'),
+ hidden: Em.computed.and('emptySummary', 'post.notDeleted'),
+ rerenderTriggers: ['actionsSummary.@each', 'post.deleted'],
+
+ // This was creating way too many bound ifs and subviews in the handlebars version.
+ renderString(buffer) {
+ if (!this.get('emptySummary')) {
+ this.get('actionsSummary').forEach(function(c) {
+ buffer.push("
");
+
+ const renderActionIf = function(property, dataAttribute, text) {
+ if (!c.get(property)) { return; }
+ buffer.push("
" + text + ".");
+ };
+
+ // TODO multi line expansion for flags
+ buffer.push(c.get('description') + '.');
+ renderActionIf('can_undo', 'undo', I18n.t("post.actions.undo." + c.get('actionType.name_key')));
+ renderActionIf('can_defer_flags', 'defer-flags', I18n.t("post.actions.defer_flags", { count: c.count }));
+ buffer.push("
");
+ });
+ }
+
+ const post = this.get('post');
+ if (!post.get('deleted')) {
+ buffer.push("" +
+ iconHTML('fa-trash-o') + ' ' +
+ Discourse.Utilities.tinyAvatar(post.get('postDeletedBy.avatar_template'), {title: post.get('postDeletedBy.username')}) +
+ Discourse.Formatter.autoUpdatingRelativeAge(new Date(post.get('postDeletedAt'))) +
+ "
");
+ }
+ },
+
+ actionTypeById(actionTypeId) {
+ return this.get('actionsSummary').findProperty('id', actionTypeId);
+ },
+
+ click(e) {
+ const $target = $(e.target);
+ let actionTypeId;
+
+ const post = this.get('post');
+
+ if (actionTypeId = $target.data('defer-flags')) {
+ this.actionTypeById(actionTypeId).deferFlags(post);
+ return false;
+ }
+
+ if (actionTypeId = $target.data('undo')) {
+ this.get('actionsSummary').findProperty('id', actionTypeId).undo(post);
+ return false;
+ }
+
+ return false;
+ }
+});
diff --git a/app/assets/javascripts/discourse/components/discourse-action-history.js.es6 b/app/assets/javascripts/discourse/components/discourse-action-history.js.es6
deleted file mode 100644
index ec38fca1ad7..00000000000
--- a/app/assets/javascripts/discourse/components/discourse-action-history.js.es6
+++ /dev/null
@@ -1,98 +0,0 @@
-import StringBuffer from 'discourse/mixins/string-buffer';
-
-export default Em.Component.extend(StringBuffer, {
- tagName: 'section',
- classNameBindings: [':post-actions', 'hidden'],
- actionsHistory: Em.computed.alias('post.actionsHistory'),
- emptyHistory: Em.computed.empty('actionsHistory'),
- hidden: Em.computed.and('emptyHistory', 'post.notDeleted'),
-
- rerenderTriggers: ['actionsHistory.@each', 'actionsHistory.users.length', 'post.deleted'],
-
- // This was creating way too many bound ifs and subviews in the handlebars version.
- renderString(buffer) {
- if (!this.get('emptyHistory')) {
- this.get('actionsHistory').forEach(function(c) {
- buffer.push("");
-
- const renderActionIf = function(property, dataAttribute, text) {
- if (!c.get(property)) { return; }
- buffer.push("
" + text + ".");
- };
-
- // TODO multi line expansion for flags
- let iconsHtml = "";
- if (c.get('usersExpanded')) {
- let postUrl;
- c.get('users').forEach(function(u) {
- iconsHtml += "
";
- if (u.post_url) {
- postUrl = postUrl || u.post_url;
- }
- iconsHtml += Discourse.Utilities.avatarImg({
- size: 'small',
- avatarTemplate: u.get('avatarTemplate'),
- title: u.get('username')
- });
- iconsHtml += "";
- });
-
- let key = 'post.actions.people.' + c.get('actionType.name_key');
- if (postUrl) { key = key + "_with_url"; }
-
- // TODO postUrl might be uninitialized? pick a good default
- buffer.push(" " + I18n.t(key, { icons: iconsHtml, postUrl: postUrl}) + ".");
- }
- renderActionIf('usersCollapsed', 'who-acted', c.get('description'));
- renderActionIf('canAlsoAction', 'act', I18n.t("post.actions.it_too." + c.get('actionType.name_key')));
- renderActionIf('can_undo', 'undo', I18n.t("post.actions.undo." + c.get('actionType.name_key')));
- renderActionIf('can_defer_flags', 'defer-flags', I18n.t("post.actions.defer_flags", { count: c.count }));
-
- buffer.push("
");
- });
- }
-
- const post = this.get('post');
- if (post.get('deleted')) {
- buffer.push("" +
- " " +
- Discourse.Utilities.tinyAvatar(post.get('postDeletedBy.avatar_template'), {title: post.get('postDeletedBy.username')}) +
- Discourse.Formatter.autoUpdatingRelativeAge(new Date(post.get('postDeletedAt'))) +
- "
");
- }
- },
-
- actionTypeById(actionTypeId) {
- return this.get('actionsHistory').findProperty('id', actionTypeId);
- },
-
- click(e) {
- const $target = $(e.target);
- let actionTypeId;
-
- const post = this.get('post');
-
- if (actionTypeId = $target.data('defer-flags')) {
- this.actionTypeById(actionTypeId).deferFlags(post);
- return false;
- }
-
- // User wants to know who actioned it
- if (actionTypeId = $target.data('who-acted')) {
- this.actionTypeById(actionTypeId).loadUsers(post);
- return false;
- }
-
- if (actionTypeId = $target.data('act')) {
- this.get('actionsHistory').findProperty('id', actionTypeId).act(post);
- return false;
- }
-
- if (actionTypeId = $target.data('undo')) {
- this.get('actionsHistory').findProperty('id', actionTypeId).undo(post);
- return false;
- }
-
- return false;
- }
-});
diff --git a/app/assets/javascripts/discourse/views/post-menu.js.es6 b/app/assets/javascripts/discourse/components/post-menu.js.es6
similarity index 60%
rename from app/assets/javascripts/discourse/views/post-menu.js.es6
rename to app/assets/javascripts/discourse/components/post-menu.js.es6
index e865eec7a26..ac3d83fa6e5 100644
--- a/app/assets/javascripts/discourse/views/post-menu.js.es6
+++ b/app/assets/javascripts/discourse/components/post-menu.js.es6
@@ -1,7 +1,8 @@
import StringBuffer from 'discourse/mixins/string-buffer';
+import { iconHTML } from 'discourse/helpers/fa-icon';
// Helper class for rendering a button
-export var Button = function(action, label, icon, opts) {
+export const Button = function(action, label, icon, opts) {
this.action = action;
this.label = label;
@@ -18,7 +19,7 @@ function animateHeart($elem, start, end, complete) {
.css('textIndent', start)
.animate({ textIndent: end }, {
complete: complete,
- step: function(now) {
+ step(now) {
$(this).css('transform','scale('+now+')');
},
duration: 150
@@ -26,9 +27,9 @@ function animateHeart($elem, start, end, complete) {
}
Button.prototype.render = function(buffer) {
- var opts = this.opts;
+ const opts = this.opts;
- var label = I18n.t(this.label);
+ const label = I18n.t(this.label);
buffer.push("");
};
-var hiddenButtons;
+let hiddenButtons;
-var PostMenuView = Discourse.View.extend(StringBuffer, {
+const PostMenuView = Ember.Component.extend(StringBuffer, {
tagName: 'section',
classNames: ['post-menu-area', 'clearfix'],
rerenderTriggers: [
'post.deleted_at',
- 'post.like_count',
+ 'likeAction.count',
+ 'likeAction.users.length',
'post.reply_count',
'post.showRepliesBelow',
'post.can_delete',
@@ -62,53 +64,71 @@ var PostMenuView = Discourse.View.extend(StringBuffer, {
'post.post_type',
'collapsed'],
+ likeAction: function() {
+ return this.get('post.actionByName.like');
+ }.property('post.actionByName.like'),
+
_collapsedByDefault: function() {
this.set('collapsed', true);
}.on('init'),
- renderString: function(buffer) {
- var post = this.get('post');
+ renderString(buffer) {
+ const post = this.get('post');
buffer.push("");
},
// Delegate click actions
- click: function(e) {
- var $target = $(e.target),
+ click(e) {
+ const $target = $(e.target),
action = $target.data('action') || $target.parent().data('action');
if (!action) return;
- var handler = this["click" + action.capitalize()];
+ const handler = this["click" + action.capitalize()];
if (!handler) return;
handler.call(this, this.get('post'));
},
// Replies Button
- renderReplies: function(post, buffer) {
+ renderReplies(post, buffer) {
if (!post.get('showRepliesBelow')) return;
- var reply_count = post.get('reply_count');
+ const replyCount = post.get('reply_count');
buffer.push("");
+ const icon = (this.get('post.replies.length') > 0) ? 'chevron-up' : 'chevron-down';
+ return buffer.push(iconHTML(icon) + "");
},
- renderButtons: function(post, buffer) {
- var self = this,
- allButtons = [],
- visibleButtons = [];
+ renderLikes(post, buffer) {
+ const likeCount = this.get('likeAction.count') || 0;
+ if (likeCount === 0) { return; }
+
+ buffer.push("");
+ },
+
+
+ renderButtons(post, buffer) {
+ const self = this;
+ const allButtons = [];
+ let visibleButtons = [];
if (typeof hiddenButtons === "undefined") {
- if (!Em.isEmpty(Discourse.SiteSettings.post_menu_hidden_items)) {
- hiddenButtons = Discourse.SiteSettings.post_menu_hidden_items.split('|');
+ if (!Em.isEmpty(this.siteSettings.post_menu_hidden_items)) {
+ hiddenButtons = this.siteSettings.post_menu_hidden_items.split('|');
} else {
hiddenButtons = [];
}
@@ -118,11 +138,11 @@ var PostMenuView = Discourse.View.extend(StringBuffer, {
hiddenButtons.removeObject("bookmark");
}
- var yours = post.get('yours');
- Discourse.SiteSettings.post_menu.split("|").forEach(function(i) {
- var creator = self["buttonFor" + i.replace(/\+/, '').capitalize()];
+ const yours = post.get('yours');
+ this.siteSettings.post_menu.split("|").forEach(function(i) {
+ const creator = self["buttonFor" + i.replace(/\+/, '').capitalize()];
if (creator) {
- var button = creator.call(self, post);
+ const button = creator.call(self, post);
if (button) {
allButtons.push(button);
if ((yours && button.opts.alwaysShowYours) ||
@@ -136,7 +156,7 @@ var PostMenuView = Discourse.View.extend(StringBuffer, {
// Only show ellipsis if there is more than one button hidden
// if there are no more buttons, we are not collapsed
- var collapsed = this.get('collapsed');
+ const collapsed = this.get('collapsed');
if (!collapsed || (allButtons.length <= visibleButtons.length + 1)) {
visibleButtons = allButtons;
if (collapsed) { this.set('collapsed', false); }
@@ -144,7 +164,7 @@ var PostMenuView = Discourse.View.extend(StringBuffer, {
visibleButtons.splice(visibleButtons.length - 1, 0, this.buttonForShowMoreActions(post));
}
- var callbacks = PostMenuView._registerButtonCallbacks;
+ const callbacks = PostMenuView._registerButtonCallbacks;
if (callbacks) {
_.each(callbacks, function(callback) {
callback.apply(self, [visibleButtons]);
@@ -152,13 +172,23 @@ var PostMenuView = Discourse.View.extend(StringBuffer, {
}
buffer.push('');
- visibleButtons.forEach(function (b) {
- b.render(buffer);
- });
+ visibleButtons.forEach((b) => b.render(buffer));
buffer.push("
");
},
- clickReplies: function() {
+ clickLikes() {
+ const likeAction = this.get('post.actionByName.like');
+ if (likeAction) {
+ const users = likeAction.get('users');
+ if (users && users.length) {
+ users.clear();
+ } else {
+ likeAction.loadUsers(this.get('post'));
+ }
+ }
+ },
+
+ clickReplies() {
if (this.get('post.replies.length') > 0) {
this.set('post.replies', []);
} else {
@@ -167,12 +197,12 @@ var PostMenuView = Discourse.View.extend(StringBuffer, {
},
// Delete button
- buttonForDelete: function(post) {
- var label, icon;
+ buttonForDelete(post) {
+ let label, icon;
if (post.get('post_number') === 1) {
// If it's the first post, the delete/undo actions are related to the topic
- var topic = post.get('topic');
+ const topic = post.get('topic');
if (topic.get('deleted_at')) {
if (!topic.get('details.can_recover')) { return; }
label = "topic.actions.recover";
@@ -195,50 +225,50 @@ var PostMenuView = Discourse.View.extend(StringBuffer, {
icon = "trash-o";
}
}
- var action = (icon === 'trash-o') ? 'delete' : 'recover';
- var opts;
+ const action = (icon === 'trash-o') ? 'delete' : 'recover';
+ let opts;
if (icon === "trash-o"){
opts = {className: 'delete'};
}
return new Button(action, label, icon, opts);
},
- clickRecover: function(post) {
- this.get('controller').send('recoverPost', post);
+ clickRecover(post) {
+ this.sendAction('recoverPost', post);
},
- clickDelete: function(post) {
- this.get('controller').send('deletePost', post);
+ clickDelete(post) {
+ this.sendAction('deletePost', post);
},
// Like button
- buttonForLike: function(post) {
- var likeAction = post.get('actionByName.like');
+ buttonForLike(post) {
+ const likeAction = this.get('likeAction');
if (!likeAction) { return; }
- var className = likeAction.get('acted') ? 'has-like' : 'like';
+ const className = likeAction.get('acted') ? 'has-like' : 'like';
if (likeAction.get('canToggle')) {
- var descKey = likeAction.get('acted') ? 'post.controls.undo_like' : 'post.controls.like';
+ const descKey = likeAction.get('acted') ? 'post.controls.undo_like' : 'post.controls.like';
return new Button('like', descKey, 'heart', {className: className});
} else if (likeAction.get('acted')) {
return new Button('like', 'post.controls.has_liked', 'heart', {className: className, disabled: true});
}
},
- clickLike: function(post) {
- var $heart = this.$('.fa-heart'),
- controller = this.get('controller'),
- $likeButton = this.$('button[data-action=like]');
+ clickLike(post) {
+ const $heart = this.$('.fa-heart'),
+ $likeButton = this.$('button[data-action=like]'),
+ acted = post.get('actionByName.like.acted'),
+ self = this;
- var acted = post.get('actionByName.like.acted');
if (acted) {
- controller.send('toggleLike', post);
+ this.sendAction('toggleLike', post);
$likeButton.removeClass('has-like').addClass('like');
} else {
- var scale = [1.0, 1.5];
+ const scale = [1.0, 1.5];
animateHeart($heart, scale[0], scale[1], function() {
animateHeart($heart, scale[1], scale[0], function() {
- controller.send('toggleLike', post);
+ self.sendAction('toggleLike', post);
$likeButton.removeClass('like').addClass('has-like');
});
});
@@ -246,17 +276,17 @@ var PostMenuView = Discourse.View.extend(StringBuffer, {
},
// Flag button
- buttonForFlag: function(post) {
+ buttonForFlag(post) {
if (Em.isEmpty(post.get('flagsAvailable'))) return;
return new Button('flag', 'post.controls.flag', 'flag');
},
- clickFlag: function(post) {
- this.get('controller').send('showFlags', post);
+ clickFlag(post) {
+ this.sendAction('showFlags', post);
},
// Edit button
- buttonForEdit: function(post) {
+ buttonForEdit(post) {
if (!post.get('can_edit')) return;
return new Button('edit', 'post.controls.edit', 'pencil', {
alwaysShowYours: true,
@@ -264,14 +294,14 @@ var PostMenuView = Discourse.View.extend(StringBuffer, {
});
},
- clickEdit: function(post) {
- this.get('controller').send('editPost', post);
+ clickEdit(post) {
+ this.sendAction('editPost', post);
},
// Share button
- buttonForShare: function(post) {
+ buttonForShare(post) {
if (!Discourse.User.current()) return;
- var options = {
+ const options = {
shareUrl: post.get('shareUrl'),
postNumber: post.get('post_number')
};
@@ -279,9 +309,9 @@ var PostMenuView = Discourse.View.extend(StringBuffer, {
},
// Reply button
- buttonForReply: function() {
- if (!this.get('controller.model.details.can_create_post')) return;
- var options = {className: 'create'};
+ buttonForReply() {
+ if (!this.get('canCreatePost')) return;
+ const options = {className: 'create'};
if(!Discourse.Mobile.mobileView) {
options.textLabel = 'topic.reply.title';
@@ -290,15 +320,15 @@ var PostMenuView = Discourse.View.extend(StringBuffer, {
return new Button('reply', 'post.controls.reply', 'reply', options);
},
- clickReply: function(post) {
- this.get('controller').send('replyToPost', post);
+ clickReply(post) {
+ this.sendAction('replyToPost', post);
},
// Bookmark button
- buttonForBookmark: function(post) {
+ buttonForBookmark(post) {
if (!Discourse.User.current()) return;
- var iconClass = 'read-icon',
+ let iconClass = 'read-icon',
buttonClass = 'bookmark',
tooltip = 'bookmarks.not_bookmarked';
@@ -311,33 +341,30 @@ var PostMenuView = Discourse.View.extend(StringBuffer, {
return new Button('bookmark', tooltip, {className: buttonClass, innerHTML: ""});
},
- clickBookmark: function(post) {
- this.get('controller').send('toggleBookmark', post);
+ clickBookmark(post) {
+ this.sendAction('toggleBookmark', post);
},
- buttonForAdmin: function() {
+ buttonForAdmin() {
if (!Discourse.User.currentProp('canManageTopic')) { return; }
return new Button('admin', 'post.controls.admin', 'wrench');
},
- renderAdminPopup: function(post, buffer) {
+ renderAdminPopup(post, buffer) {
if (!Discourse.User.currentProp('canManageTopic')) { return; }
- var isWiki = post.get('wiki'),
- wikiIcon = '',
- wikiText = isWiki ? I18n.t('post.controls.unwiki') : I18n.t('post.controls.wiki');
+ const isWiki = post.get('wiki'),
+ wikiIcon = iconHTML('pencil-square-o'),
+ wikiText = isWiki ? I18n.t('post.controls.unwiki') : I18n.t('post.controls.wiki'),
+ isModerator = post.get('post_type') === this.site.get('post_types.moderator_action'),
+ postTypeIcon = iconHTML('shield'),
+ postTypeText = isModerator ? I18n.t('post.controls.revert_to_regular') : I18n.t('post.controls.convert_to_moderator'),
+ rebakePostIcon = iconHTML('cog'),
+ rebakePostText = I18n.t('post.controls.rebake'),
+ unhidePostIcon = iconHTML('eye'),
+ unhidePostText = I18n.t('post.controls.unhide');
- var isModerator = post.get('post_type') === Discourse.Site.currentProp('post_types.moderator_action'),
- postTypeIcon = '',
- postTypeText = isModerator ? I18n.t('post.controls.revert_to_regular') : I18n.t('post.controls.convert_to_moderator');
-
- var rebakePostIcon = '',
- rebakePostText = I18n.t('post.controls.rebake');
-
- var unhidePostIcon = '',
- unhidePostText = I18n.t('post.controls.unhide');
-
- var html = '
diff --git a/app/assets/javascripts/main_include.js b/app/assets/javascripts/main_include.js
index 67de20ffe60..ddaf3d90c31 100644
--- a/app/assets/javascripts/main_include.js
+++ b/app/assets/javascripts/main_include.js
@@ -27,6 +27,7 @@
//= require_tree ./discourse/adapters
//= require ./discourse/models/rest
//= require ./discourse/models/model
+//= require ./discourse/models/post-action-type
//= require ./discourse/models/post
//= require ./discourse/models/post-stream
//= require ./discourse/models/topic-details
diff --git a/app/assets/stylesheets/common/base/topic-post.scss b/app/assets/stylesheets/common/base/topic-post.scss
index e0b4f0762d8..f0d8a173e14 100644
--- a/app/assets/stylesheets/common/base/topic-post.scss
+++ b/app/assets/stylesheets/common/base/topic-post.scss
@@ -233,3 +233,11 @@ blockquote > *:last-child {
}
}
+
+.who-liked {
+ a {
+ margin: 0 0.25em 0.5em 0;
+ display: inline-block;
+ }
+}
+
diff --git a/app/assets/stylesheets/desktop/topic-post.scss b/app/assets/stylesheets/desktop/topic-post.scss
index 692756022ed..233513bfd63 100644
--- a/app/assets/stylesheets/desktop/topic-post.scss
+++ b/app/assets/stylesheets/desktop/topic-post.scss
@@ -95,7 +95,7 @@ nav.post-controls {
}
}
- .show-replies {
+ .show-replies, .show-likes {
margin-left: 0;
font-size: inherit;
span.badge-posts {color: scale-color($primary, $lightness: 60%);}
diff --git a/app/assets/stylesheets/mobile/topic-post.scss b/app/assets/stylesheets/mobile/topic-post.scss
index 3fa744b2fee..9da264cfeb1 100644
--- a/app/assets/stylesheets/mobile/topic-post.scss
+++ b/app/assets/stylesheets/mobile/topic-post.scss
@@ -27,6 +27,21 @@ span.badge-posts {
display: none;
}
+.show-likes {
+ margin-left: 0;
+ padding-left: 0;
+ padding-right: 0;
+ font-size: inherit;
+ span.badge-posts {color: scale-color($primary, $lightness: 60%);}
+ &:hover {
+ background: dark-light-diff($primary, $secondary, 90%, -65%);
+ span.badge-posts {color: $primary;}
+ }
+ i {
+ display: none;
+ }
+}
+
nav.post-controls {
clear: both;
}
diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml
index e637b4a17bb..25fe84f2a55 100644
--- a/config/locales/client.en.yml
+++ b/config/locales/client.en.yml
@@ -1233,6 +1233,9 @@ en:
has_replies:
one: "Reply"
other: "Replies"
+ has_likes:
+ one: "Like"
+ other: "Likes"
errors:
create: "Sorry, there was an error creating your post. Please try again."
diff --git a/test/javascripts/controllers/flag-test.js.es6 b/test/javascripts/controllers/flag-test.js.es6
index 686f3d20151..beb5dd9af6e 100644
--- a/test/javascripts/controllers/flag-test.js.es6
+++ b/test/javascripts/controllers/flag-test.js.es6
@@ -1,3 +1,5 @@
+import createStore from 'helpers/create-store';
+
var buildPost = function(args) {
return Discourse.Post.create(_.merge({
id: 1,
@@ -18,14 +20,21 @@ moduleFor("controller:flag", "controller:flag", {
});
test("canDeleteSpammer not staff", function(){
+ const store = createStore();
+
var flagController = this.subject({ model: buildPost() });
sandbox.stub(Discourse.User, 'currentProp').withArgs('staff').returns(false);
- flagController.set('selected', Discourse.PostActionType.create({name_key: 'spam'}));
+
+ const spamFlag = store.createRecord('post-action-type', {name_key: 'spam'});
+ flagController.set('selected', spamFlag);
equal(flagController.get('canDeleteSpammer'), false, 'false if current user is not staff');
});
var canDeleteSpammer = function(flagController, postActionType, expected, testName) {
- flagController.set('selected', Discourse.PostActionType.create({name_key: postActionType}));
+ const store = createStore();
+ const flag = store.createRecord('post-action-type', {name_key: postActionType});
+ flagController.set('selected', flag);
+
equal(flagController.get('canDeleteSpammer'), expected, testName);
};
diff --git a/test/javascripts/test_helper.js b/test/javascripts/test_helper.js
index e29c25cd249..f93e3879814 100644
--- a/test/javascripts/test_helper.js
+++ b/test/javascripts/test_helper.js
@@ -81,15 +81,19 @@ var origDebounce = Ember.run.debounce,
flushMap = require('discourse/models/store', null, null, false).flushMap,
server;
+function dup(obj) {
+ return jQuery.extend(true, {}, obj);
+}
+
QUnit.testStart(function(ctx) {
server = createPretendServer();
// Allow our tests to change site settings and have them reset before the next test
- Discourse.SiteSettings = jQuery.extend(true, {}, Discourse.SiteSettingsOriginal);
+ Discourse.SiteSettings = dup(Discourse.SiteSettingsOriginal);
Discourse.BaseUri = "/";
Discourse.BaseUrl = "localhost";
Discourse.User.resetCurrent();
- Discourse.Site.resetCurrent(Discourse.Site.create(fixtures['site.json'].site));
+ Discourse.Site.resetCurrent(Discourse.Site.create(dup(fixtures['site.json'].site)));
Discourse.URL.redirectedTo = null;
Discourse.URL.redirectTo = function(url) {