From 6f36d5996db0d5313e4e32a832e7a9fe416bd842 Mon Sep 17 00:00:00 2001 From: Robin Ward <robin.ward@gmail.com> Date: Wed, 30 Jul 2014 18:56:01 -0400 Subject: [PATCH] Lots of work on tests --- .jshintrc | 7 +-- .../admin_badges_controller_test.js | 4 +- .../admin/models/admin_user_test.js | 6 +- test/javascripts/admin/models/api_key_test.js | 10 ++-- .../admin/models/flagged_post_test.js | 4 +- .../components/home_logo_component_test.js | 1 + .../keyboard_shortcuts_component_test.js | 52 ++++++++--------- .../controllers/flag_controller_test.js | 49 ++++++++-------- .../controllers/header_controller_test.js | 11 ++-- .../controllers/search_controller_test.js | 50 ++++++++-------- .../site_map_category_controller_test.js | 11 +--- .../controllers/site_map_controller_test.js | 26 ++++++--- .../user_dropdown_controller_test.js | 13 ++--- test/javascripts/fixtures/user_fixtures.js | 2 +- test/javascripts/helpers/parse_html.js | 2 +- test/javascripts/helpers/qunit_helpers.js | 18 +----- test/javascripts/integration/header-test.js | 4 +- test/javascripts/lib/click_track_test.js | 47 +++++++-------- test/javascripts/lib/computed_test.js | 2 +- test/javascripts/lib/html_test.js | 2 +- test/javascripts/lib/onebox_test.js | 4 +- test/javascripts/lib/url_test.js | 8 +-- test/javascripts/lib/utilities_test.js | 12 ++-- .../mixins/has_current_user_test.js | 2 +- test/javascripts/mixins/presence_test.js | 2 +- test/javascripts/mixins/singleton_test.js | 2 +- test/javascripts/models/badge_test.js | 10 ++-- test/javascripts/models/category_test.js | 4 +- test/javascripts/models/composer_test.js | 12 ++-- test/javascripts/models/email_log_test.js | 2 +- test/javascripts/models/invite_test.js | 2 +- test/javascripts/models/post_stream_test.js | 18 +++--- test/javascripts/models/post_test.js | 4 +- test/javascripts/models/session_test.js | 2 +- test/javascripts/models/site_test.js | 2 +- .../models/staff_action_log_test.js | 2 +- test/javascripts/models/topic_test.js | 6 +- test/javascripts/models/user_badge_test.js | 8 +-- test/javascripts/templates/site_map_test.js | 5 +- test/javascripts/test_helper.js | 17 ++++-- test/javascripts/views/container_view_test.js | 49 ++++++++-------- test/javascripts/views/header_view_test.js | 7 +-- test/javascripts/views/text_field_test.js | 58 +++---------------- 43 files changed, 248 insertions(+), 311 deletions(-) diff --git a/.jshintrc b/.jshintrc index 6c4721ea2..f7f699b5e 100644 --- a/.jshintrc +++ b/.jshintrc @@ -12,7 +12,10 @@ "bootbox", "module", "moduleFor", + "moduleForComponent", + "sandbox", "integration", + "controllerFor", "test", "ok", "not", @@ -39,10 +42,6 @@ "start", "_", "alert", - "controllerFor", - "viewClassFor", - "componentClassFor", - "testController", "containsInstance", "parseHTML", "deepEqual", diff --git a/test/javascripts/admin/controllers/admin_badges_controller_test.js b/test/javascripts/admin/controllers/admin_badges_controller_test.js index 16a126deb..793fd6236 100644 --- a/test/javascripts/admin/controllers/admin_badges_controller_test.js +++ b/test/javascripts/admin/controllers/admin_badges_controller_test.js @@ -32,7 +32,7 @@ test("save", function() { controller = this.subject({ model: [badge, otherBadge] }); controller.send('selectBadge', badge); - sinon.stub(badge, "save").returns(Ember.RSVP.resolve({})); + sandbox.stub(badge, "save").returns(Ember.RSVP.resolve({})); controller.send("save"); ok(badge.save.calledOnce, "called save on the badge"); }); @@ -42,7 +42,7 @@ test("destroy", function() { otherBadge = Discourse.Badge.create({id: 102, name: "Other Badge"}), controller = this.subject({model: [badge, otherBadge]}); - sinon.stub(badge, 'destroy').returns(Ember.RSVP.resolve({})); + sandbox.stub(badge, 'destroy').returns(Ember.RSVP.resolve({})); bootbox.confirm = function(text, yes, no, func) { func(false); diff --git a/test/javascripts/admin/models/admin_user_test.js b/test/javascripts/admin/models/admin_user_test.js index 172bc481f..0ea725f36 100644 --- a/test/javascripts/admin/models/admin_user_test.js +++ b/test/javascripts/admin/models/admin_user_test.js @@ -2,7 +2,7 @@ module("Discourse.AdminUser"); asyncTestDiscourse('generate key', function() { - this.stub(Discourse, 'ajax').returns(Ember.RSVP.resolve({api_key: {id: 1234, key: 'asdfasdf'}})); + sandbox.stub(Discourse, 'ajax').returns(Ember.RSVP.resolve({api_key: {id: 1234, key: 'asdfasdf'}})); var adminUser = Discourse.AdminUser.create({id: 333}); @@ -19,7 +19,7 @@ asyncTestDiscourse('revoke key', function() { var apiKey = Discourse.ApiKey.create({id: 1234, key: 'asdfasdf'}), adminUser = Discourse.AdminUser.create({id: 333, api_key: apiKey}); - this.stub(Discourse, 'ajax').returns(Ember.RSVP.resolve()); + sandbox.stub(Discourse, 'ajax').returns(Ember.RSVP.resolve()); equal(adminUser.get('api_key'), apiKey, 'it has the api key in the beginning'); adminUser.revokeApiKey().then(function() { @@ -27,4 +27,4 @@ asyncTestDiscourse('revoke key', function() { ok(Discourse.ajax.calledWith("/admin/users/333/revoke_api_key", { type: 'DELETE' }), "it DELETEd to the url"); blank(adminUser.get('api_key'), 'it cleared the api_key'); }); -}); \ No newline at end of file +}); diff --git a/test/javascripts/admin/models/api_key_test.js b/test/javascripts/admin/models/api_key_test.js index fd26de7f9..44da70908 100644 --- a/test/javascripts/admin/models/api_key_test.js +++ b/test/javascripts/admin/models/api_key_test.js @@ -9,7 +9,7 @@ test('create', function() { asyncTestDiscourse('find', function() { - this.stub(Discourse, 'ajax').returns(Ember.RSVP.resolve([])); + sandbox.stub(Discourse, 'ajax').returns(Ember.RSVP.resolve([])); Discourse.ApiKey.find().then(function() { start(); ok(Discourse.ajax.calledWith("/admin/api"), "it GETs the keys"); @@ -17,7 +17,7 @@ asyncTestDiscourse('find', function() { }); asyncTestDiscourse('generateMasterKey', function() { - this.stub(Discourse, 'ajax').returns(Ember.RSVP.resolve({api_key: {}})); + sandbox.stub(Discourse, 'ajax').returns(Ember.RSVP.resolve({api_key: {}})); Discourse.ApiKey.generateMasterKey().then(function() { start(); ok(Discourse.ajax.calledWith("/admin/api/key", {type: 'POST'}), "it POSTs to create a master key"); @@ -27,7 +27,7 @@ asyncTestDiscourse('generateMasterKey', function() { asyncTestDiscourse('regenerate', function() { var apiKey = Discourse.ApiKey.create({id: 3456}); - this.stub(Discourse, 'ajax').returns(Ember.RSVP.resolve({api_key: {id: 3456}})); + sandbox.stub(Discourse, 'ajax').returns(Ember.RSVP.resolve({api_key: {id: 3456}})); apiKey.regenerate().then(function() { start(); ok(Discourse.ajax.calledWith("/admin/api/key", {type: 'PUT', data: {id: 3456}}), "it PUTs the key"); @@ -37,9 +37,9 @@ asyncTestDiscourse('regenerate', function() { asyncTestDiscourse('revoke', function() { var apiKey = Discourse.ApiKey.create({id: 3456}); - this.stub(Discourse, 'ajax').returns(Ember.RSVP.resolve([])); + sandbox.stub(Discourse, 'ajax').returns(Ember.RSVP.resolve([])); apiKey.revoke().then(function() { start(); ok(Discourse.ajax.calledWith("/admin/api/key", {type: 'DELETE', data: {id: 3456}}), "it DELETES the key"); }); -}); \ No newline at end of file +}); diff --git a/test/javascripts/admin/models/flagged_post_test.js b/test/javascripts/admin/models/flagged_post_test.js index e59441ff7..bf26a0664 100644 --- a/test/javascripts/admin/models/flagged_post_test.js +++ b/test/javascripts/admin/models/flagged_post_test.js @@ -1,7 +1,7 @@ module("Discourse.FlaggedPost"); test('delete first post', function() { - this.stub(Discourse, 'ajax'); + sandbox.stub(Discourse, 'ajax'); Discourse.FlaggedPost.create({ id: 1, topic_id: 2, post_number: 1 }) .deletePost(); @@ -10,7 +10,7 @@ test('delete first post', function() { }); test('delete second post', function() { - this.stub(Discourse, 'ajax'); + sandbox.stub(Discourse, 'ajax'); Discourse.FlaggedPost.create({ id: 1, topic_id: 2, post_number: 2 }) .deletePost(); diff --git a/test/javascripts/components/home_logo_component_test.js b/test/javascripts/components/home_logo_component_test.js index c6b884322..01822988c 100644 --- a/test/javascripts/components/home_logo_component_test.js +++ b/test/javascripts/components/home_logo_component_test.js @@ -48,6 +48,7 @@ module("Discourse.HomeLogoComponent", { teardown: function() { Discourse.Mobile.mobileView = oldMobileView; + Discourse.reset(); } }); diff --git a/test/javascripts/components/keyboard_shortcuts_component_test.js b/test/javascripts/components/keyboard_shortcuts_component_test.js index 655a33de2..186577927 100644 --- a/test/javascripts/components/keyboard_shortcuts_component_test.js +++ b/test/javascripts/components/keyboard_shortcuts_component_test.js @@ -1,11 +1,13 @@ +var testMouseTrap; + module("Discourse.KeyboardShortcuts", { setup: function() { - this.testMouseTrap = { - bindings: {}, + var _bindings = {}; + testMouseTrap = { bind: function(bindings, callback) { var registerBinding = _.bind(function(binding) { - this.bindings[binding] = callback; + _bindings[binding] = callback; }, this); if (_.isArray(bindings)) { @@ -17,11 +19,11 @@ module("Discourse.KeyboardShortcuts", { }, trigger: function(binding) { - this.bindings[binding].call(); + _bindings[binding].call(); } }; - sinon.stub(Discourse.URL, "routeTo"); + sandbox.stub(Discourse.URL, "routeTo"); $("#qunit-fixture").html([ "<article class='topic-post selected'>", @@ -54,8 +56,6 @@ module("Discourse.KeyboardShortcuts", { teardown: function() { $("#qunit-scratch").html(""); - - Discourse.URL.routeTo.restore(); } }); @@ -65,8 +65,8 @@ _.each(pathBindings, function(path, binding) { var testName = binding + " goes to " + path; test(testName, function() { - Discourse.KeyboardShortcuts.bindEvents(this.testMouseTrap); - this.testMouseTrap.trigger(binding); + Discourse.KeyboardShortcuts.bindEvents(testMouseTrap); + testMouseTrap.trigger(binding); ok(Discourse.URL.routeTo.calledWith(path)); }); @@ -79,14 +79,14 @@ _.each(clickBindings, function(selector, binding) { var testName = binding + " clicks on " + selector; - test(testName, bindings.length, function() { - Discourse.KeyboardShortcuts.bindEvents(this.testMouseTrap); + test(testName, function() { + Discourse.KeyboardShortcuts.bindEvents(testMouseTrap); $(selector).on("click", function() { ok(true, selector + " was clicked"); }); _.each(bindings, function(binding) { - this.testMouseTrap.trigger(binding); + testMouseTrap.trigger(binding); }, this); }); }); @@ -97,55 +97,49 @@ _.each(functionBindings, function(func, binding) { var testName = binding + " calls " + func; test(testName, function() { - var stub = sinon.stub(Discourse.KeyboardShortcuts, func, function() { + sandbox.stub(Discourse.KeyboardShortcuts, func, function() { ok(true, func + " is called when " + binding + " is triggered"); }); - Discourse.KeyboardShortcuts.bindEvents(this.testMouseTrap); + Discourse.KeyboardShortcuts.bindEvents(testMouseTrap); - this.testMouseTrap.trigger(binding); - stub.restore(); + testMouseTrap.trigger(binding); }); }); test("selectDown calls _moveSelection with 1", function() { - var spy = sinon.spy(Discourse.KeyboardShortcuts, '_moveSelection'); + var spy = sandbox.spy(Discourse.KeyboardShortcuts, '_moveSelection'); Discourse.KeyboardShortcuts.selectDown(); ok(spy.calledWith(1), "_moveSelection is called with 1"); - spy.restore(); }); test("selectUp calls _moveSelection with -1", function() { - var spy = sinon.spy(Discourse.KeyboardShortcuts, '_moveSelection'); + var spy = sandbox.spy(Discourse.KeyboardShortcuts, '_moveSelection'); Discourse.KeyboardShortcuts.selectUp(); ok(spy.calledWith(-1), "_moveSelection is called with -1"); - spy.restore(); }); test("goBack calls history.back", function() { - var called = false, - stub = sinon.stub(history, 'back', function() { - called = true; - }); + var called = false; + sandbox.stub(history, 'back', function() { + called = true; + }); Discourse.KeyboardShortcuts.goBack(); ok(called, "history.back is called"); - stub.restore(); }); test("nextSection calls _changeSection with 1", function() { - var spy = sinon.spy(Discourse.KeyboardShortcuts, '_changeSection'); + var spy = sandbox.spy(Discourse.KeyboardShortcuts, '_changeSection'); Discourse.KeyboardShortcuts.nextSection(); ok(spy.calledWith(1), "_changeSection is called with 1"); - spy.restore(); }); test("prevSection calls _changeSection with -1", function() { - var spy = sinon.spy(Discourse.KeyboardShortcuts, '_changeSection'); + var spy = sandbox.spy(Discourse.KeyboardShortcuts, '_changeSection'); Discourse.KeyboardShortcuts.prevSection(); ok(spy.calledWith(-1), "_changeSection is called with -1"); - spy.restore(); }); diff --git a/test/javascripts/controllers/flag_controller_test.js b/test/javascripts/controllers/flag_controller_test.js index bea4949fe..686f3d201 100644 --- a/test/javascripts/controllers/flag_controller_test.js +++ b/test/javascripts/controllers/flag_controller_test.js @@ -13,43 +13,44 @@ var buildAdminUser = function(args) { }, args || {})); }; -moduleFor("controller:flag"); +moduleFor("controller:flag", "controller:flag", { + needs: ['controller:modal'] +}); test("canDeleteSpammer not staff", function(){ - var flagController = controllerFor('flag', buildPost()); - this.stub(Discourse.User, 'currentProp').withArgs('staff').returns(false); + var flagController = this.subject({ model: buildPost() }); + sandbox.stub(Discourse.User, 'currentProp').withArgs('staff').returns(false); flagController.set('selected', Discourse.PostActionType.create({name_key: 'spam'})); equal(flagController.get('canDeleteSpammer'), false, 'false if current user is not staff'); }); -var canDeleteSpammer = function(test, postActionType, expected, testName) { - test.flagController.set('selected', Discourse.PostActionType.create({name_key: postActionType})); - equal(test.flagController.get('canDeleteSpammer'), expected, testName); +var canDeleteSpammer = function(flagController, postActionType, expected, testName) { + flagController.set('selected', Discourse.PostActionType.create({name_key: postActionType})); + equal(flagController.get('canDeleteSpammer'), expected, testName); }; test("canDeleteSpammer spam not selected", function(){ - this.stub(Discourse.User, 'currentProp').withArgs('staff').returns(true); - this.flagController = controllerFor('flag', buildPost()); - this.flagController.set('userDetails', buildAdminUser({can_delete_all_posts: true, can_be_deleted: true})); - canDeleteSpammer(this, 'off_topic', false, 'false if current user is staff, but selected is off_topic'); - canDeleteSpammer(this, 'inappropriate', false, 'false if current user is staff, but selected is inappropriate'); - canDeleteSpammer(this, 'notify_user', false, 'false if current user is staff, but selected is notify_user'); - canDeleteSpammer(this, 'notify_moderators', false, 'false if current user is staff, but selected is notify_moderators'); + sandbox.stub(Discourse.User, 'currentProp').withArgs('staff').returns(true); + var flagController = this.subject({ model: buildPost() }); + flagController.set('userDetails', buildAdminUser({can_delete_all_posts: true, can_be_deleted: true})); + canDeleteSpammer(flagController, 'off_topic', false, 'false if current user is staff, but selected is off_topic'); + canDeleteSpammer(flagController, 'inappropriate', false, 'false if current user is staff, but selected is inappropriate'); + canDeleteSpammer(flagController, 'notify_user', false, 'false if current user is staff, but selected is notify_user'); + canDeleteSpammer(flagController, 'notify_moderators', false, 'false if current user is staff, but selected is notify_moderators'); }); test("canDeleteSpammer spam selected", function(){ - this.stub(Discourse.User, 'currentProp').withArgs('staff').returns(true); - this.flagController = controllerFor('flag', buildPost()); + sandbox.stub(Discourse.User, 'currentProp').withArgs('staff').returns(true); + var flagController = this.subject({ model: buildPost() }); + flagController.set('userDetails', buildAdminUser({can_delete_all_posts: true, can_be_deleted: true})); + canDeleteSpammer(flagController, 'spam', true, 'true if current user is staff, selected is spam, posts and user can be deleted'); - this.flagController.set('userDetails', buildAdminUser({can_delete_all_posts: true, can_be_deleted: true})); - canDeleteSpammer(this, 'spam', true, 'true if current user is staff, selected is spam, posts and user can be deleted'); + flagController.set('userDetails', buildAdminUser({can_delete_all_posts: false, can_be_deleted: true})); + canDeleteSpammer(flagController, 'spam', false, 'false if current user is staff, selected is spam, posts cannot be deleted'); - this.flagController.set('userDetails', buildAdminUser({can_delete_all_posts: false, can_be_deleted: true})); - canDeleteSpammer(this, 'spam', false, 'false if current user is staff, selected is spam, posts cannot be deleted'); + flagController.set('userDetails', buildAdminUser({can_delete_all_posts: true, can_be_deleted: false})); + canDeleteSpammer(flagController, 'spam', false, 'false if current user is staff, selected is spam, user cannot be deleted'); - this.flagController.set('userDetails', buildAdminUser({can_delete_all_posts: true, can_be_deleted: false})); - canDeleteSpammer(this, 'spam', false, 'false if current user is staff, selected is spam, user cannot be deleted'); - - this.flagController.set('userDetails', buildAdminUser({can_delete_all_posts: false, can_be_deleted: false})); - canDeleteSpammer(this, 'spam', false, 'false if current user is staff, selected is spam, user cannot be deleted'); + flagController.set('userDetails', buildAdminUser({can_delete_all_posts: false, can_be_deleted: false})); + canDeleteSpammer(flagController, 'spam', false, 'false if current user is staff, selected is spam, user cannot be deleted'); }); diff --git a/test/javascripts/controllers/header_controller_test.js b/test/javascripts/controllers/header_controller_test.js index be5b8ca2b..ead441172 100644 --- a/test/javascripts/controllers/header_controller_test.js +++ b/test/javascripts/controllers/header_controller_test.js @@ -1,4 +1,4 @@ -module("controller:header", "Header Controller"); +moduleFor("controller:header", "controller:header"); test("showNotifications action", function() { var resolveRequestWith; @@ -6,17 +6,15 @@ test("showNotifications action", function() { resolveRequestWith = resolve; }); - - var controller = controllerFor('header'); + var controller = this.subject(); var viewSpy = { showDropdownBySelector: sinon.spy() }; - this.stub(Discourse, "ajax").withArgs("/notifications").returns(request); - this.stub(Discourse.User, "current").returns(Discourse.User.create({ + sandbox.stub(Discourse, "ajax").withArgs("/notifications").returns(request); + sandbox.stub(Discourse.User, "current").returns(Discourse.User.create({ unread_notifications: 1 })); - Ember.run(function() { controller.send("showNotifications", viewSpy); }); @@ -25,7 +23,6 @@ test("showNotifications action", function() { equal(Discourse.User.current().get("unread_notifications"), 1, "current user's unread notifications count is not zeroed before data has finished loading"); ok(viewSpy.showDropdownBySelector.calledWith("#user-notifications"), "dropdown with loading glyph is shown before data has finished loading"); - Ember.run(function() { resolveRequestWith(["notification"]); }); diff --git a/test/javascripts/controllers/search_controller_test.js b/test/javascripts/controllers/search_controller_test.js index 2dfbc5db8..277d80e1a 100644 --- a/test/javascripts/controllers/search_controller_test.js +++ b/test/javascripts/controllers/search_controller_test.js @@ -1,25 +1,16 @@ -var controller, searcherStub; +var searcherStub; -module("controller:search", { +moduleFor("controller:search", "controller:search", { setup: function() { Discourse.SiteSettings.min_search_term_length = 2; - // cancels debouncing behavior (calls the debounced function immediately) - sinon.stub(Ember.run, "debounce").callsArg(1); - searcherStub = Ember.Deferred.create(); - sinon.stub(Discourse.Search, "forTerm").returns(searcherStub); - - controller = testController('search', []); - }, - - teardown: function() { - Ember.run.debounce.restore(); - Discourse.Search.forTerm.restore(); + sandbox.stub(Discourse.Search, "forTerm").returns(searcherStub); } }); test("when no search term is typed yet", function() { + var controller = this.subject(); ok(!controller.get("loading"), "loading flag is false"); ok(!controller.get("noResults"), "noResults flag is false"); deepEqual(controller.get("content"), [], "content is empty"); @@ -28,9 +19,8 @@ test("when no search term is typed yet", function() { }); test("when user started typing a search term but did not reach the minimum character count threshold yet", function() { - Ember.run(function() { - controller.set("term", "a"); - }); + var controller = this.subject(); + controller.set("term", "a"); ok(!controller.get("loading"), "loading flag is false"); ok(!controller.get("noResults"), "noResults flag is false"); @@ -40,10 +30,8 @@ test("when user started typing a search term but did not reach the minimum chara }); test("when user typed a search term that is equal to or exceeds the minimum character count threshold, but results have not yet finished loading", function() { - Ember.run(function() { - controller.set("term", "ab"); - }); - + var controller = this.subject(); + controller.set("term", "ab"); ok(controller.get("loading"), "loading flag is true"); ok(!controller.get("noResults"), "noResults flag is false"); deepEqual(controller.get("content"), [], "content is empty"); @@ -52,9 +40,10 @@ test("when user typed a search term that is equal to or exceeds the minimum char }); test("when user typed a search term that is equal to or exceeds the minimum character count threshold and results have finished loading, but there are no results found", function() { - Ember.run(function() { - controller.set("term", "ab"); + var controller = this.subject(); + Em.run(function() { searcherStub.resolve([]); + controller.set("term", "ab"); }); ok(!controller.get("loading"), "loading flag is false"); @@ -65,7 +54,8 @@ test("when user typed a search term that is equal to or exceeds the minimum char }); test("when user typed a search term that is equal to or exceeds the minimum character count threshold and results have finished loading, and there are results found", function() { - Ember.run(function() { + var controller = this.subject(); + Em.run(function() { controller.set("term", "ab"); searcherStub.resolve([{ type: "user", @@ -84,7 +74,8 @@ test("when user typed a search term that is equal to or exceeds the minimum char }); test("starting to type a new term resets the previous search results", function() { - Ember.run(function() { + var controller = this.subject(); + Em.run.next(function() { controller.set("term", "ab"); searcherStub.resolve([ { @@ -106,7 +97,8 @@ test("starting to type a new term resets the previous search results", function( }); test("search results from the server are correctly reformatted (sections are sorted, section fields are preserved, item sorting is preserved, item fields are preserved, items are globally indexed across all sections)", function() { - Ember.run(function() { + var controller = this.subject(); + Em.run(function() { controller.set("term", "ab"); searcherStub.resolve([ { @@ -165,7 +157,8 @@ test("search results from the server are correctly reformatted (sections are sor }); test("keyboard navigation", function() { - Ember.run(function() { + var controller = this.subject(); + Em.run(function() { controller.set("term", "ab"); searcherStub.resolve([ { @@ -197,8 +190,9 @@ test("keyboard navigation", function() { }); test("selecting a highlighted item", function() { - this.stub(Discourse.URL, "routeTo"); + sandbox.stub(Discourse.URL, "routeTo"); + var controller = this.subject(); Ember.run(function() { controller.set("term", "ab"); searcherStub.resolve([ @@ -233,6 +227,7 @@ test("selecting a highlighted item", function() { }); test("search query / the flow of the search", function() { + var controller = this.subject(); Ember.run(function() { controller.set("searchContext", "context"); controller.set("searchContextEnabled", true); @@ -279,6 +274,7 @@ test("search query / the flow of the search", function() { }); test("typing new term when the results are filtered by type cancels type filter", function() { + var controller = this.subject(); Ember.run(function() { controller.set("term", "ab"); controller.send("moreOfType", "topic"); diff --git a/test/javascripts/controllers/site_map_category_controller_test.js b/test/javascripts/controllers/site_map_category_controller_test.js index a51c41335..2c7eef736 100644 --- a/test/javascripts/controllers/site_map_category_controller_test.js +++ b/test/javascripts/controllers/site_map_category_controller_test.js @@ -1,13 +1,8 @@ -var controller; - -module("controller:site-map-category", { - setup: function() { - controller = testController('site-map-category'); - } -}); +moduleFor("controller:site-map-category"); test("showBadges", function() { - this.stub(Discourse.User, "current"); + sandbox.stub(Discourse.User, "current"); + var controller = this.subject(); Discourse.User.current.returns(null); ok(!controller.get("showBadges"), "returns false when no user is logged in"); diff --git a/test/javascripts/controllers/site_map_controller_test.js b/test/javascripts/controllers/site_map_controller_test.js index b0fc3f386..34a722fd9 100644 --- a/test/javascripts/controllers/site_map_controller_test.js +++ b/test/javascripts/controllers/site_map_controller_test.js @@ -1,10 +1,8 @@ -var controller, oldMobileView; +var oldMobileView; -module("controller:site-map", { +moduleFor("controller:site-map", "controller:site-map", { setup: function() { oldMobileView = Discourse.Mobile.mobileView; - - controller = testController('site-map'); }, teardown: function() { @@ -13,14 +11,15 @@ module("controller:site-map", { }); test("itemController", function() { - equal(controller.get("itemController"), "site-map-category", "defaults to site-map-category"); + equal(this.subject().get("itemController"), "site-map-category", "defaults to site-map-category"); }); test("showAdminLinks", function() { var currentUserStub = Ember.Object.create(); - this.stub(Discourse.User, "current").returns(currentUserStub); + sandbox.stub(Discourse.User, "current").returns(currentUserStub); currentUserStub.set("staff", true); + var controller = this.subject(); equal(controller.get("showAdminLinks"), true, "is true when current user is a staff member"); currentUserStub.set("staff", false); @@ -29,9 +28,10 @@ test("showAdminLinks", function() { test("flaggedPostsCount", function() { var currentUserStub = Ember.Object.create(); - this.stub(Discourse.User, "current").returns(currentUserStub); + sandbox.stub(Discourse.User, "current").returns(currentUserStub); currentUserStub.set("site_flagged_posts_count", 5); + var controller = this.subject(); equal(controller.get("flaggedPostsCount"), 5, "returns current user's flagged posts count"); currentUserStub.set("site_flagged_posts_count", 0); @@ -40,46 +40,54 @@ test("flaggedPostsCount", function() { test("faqUrl returns faq url configured in site settings if it is set", function() { Discourse.SiteSettings.faq_url = "faq-url"; + var controller = this.subject(); equal(controller.get("faqUrl"), "faq-url"); }); test("faqUrl returns default '/faq' url when there is no corresponding site setting set", function() { Discourse.SiteSettings.faq_url = null; + var controller = this.subject(); equal(controller.get("faqUrl"), "/faq"); }); test("showMoblieToggle returns true when mobile theme is enabled in site settings", function() { Discourse.SiteSettings.enable_mobile_theme = true; Discourse.Mobile.isMobileDevice = true; + var controller = this.subject(); equal(controller.get("showMobileToggle"), true); }); test("showMoblieToggle returns false when mobile theme is disabled in site settings", function() { Discourse.SiteSettings.enable_mobile_theme = false; Discourse.Mobile.isMobileDevice = true; + var controller = this.subject(); equal(controller.get("showMobileToggle"), false); }); test("mobileViewLinkTextKey returns translation key for a desktop view if the current view is mobile view", function() { Discourse.Mobile.mobileView = true; + var controller = this.subject(); equal(controller.get("mobileViewLinkTextKey"), "desktop_view"); }); test("mobileViewLinkTextKey returns translation key for a mobile view if the current view is desktop view", function() { Discourse.Mobile.mobileView = false; + var controller = this.subject(); equal(controller.get("mobileViewLinkTextKey"), "mobile_view"); }); test("categories", function() { var categoryListStub = ["category1", "category2"]; - this.stub(Discourse.Category, "list").returns(categoryListStub); + sandbox.stub(Discourse.Category, "list").returns(categoryListStub); + var controller = this.subject(); deepEqual(controller.get("categories"), categoryListStub, "returns the list of categories"); }); test("toggleMobleView", function() { - this.stub(Discourse.Mobile, "toggleMobileView"); + sandbox.stub(Discourse.Mobile, "toggleMobileView"); + var controller = this.subject(); controller.send("toggleMobileView"); ok(Discourse.Mobile.toggleMobileView.calledOnce, "switches between desktop and mobile views"); }); diff --git a/test/javascripts/controllers/user_dropdown_controller_test.js b/test/javascripts/controllers/user_dropdown_controller_test.js index ab57cebc8..e45dca0ae 100644 --- a/test/javascripts/controllers/user_dropdown_controller_test.js +++ b/test/javascripts/controllers/user_dropdown_controller_test.js @@ -1,16 +1,10 @@ -var controller; - -module("controller:user-dropdown", { - setup: function() { - controller = testController('user-dropdown'); - } -}); +moduleFor("controller:user-dropdown"); test("logout action logs out the current user", function () { var logout_mock = sinon.mock(Discourse, "logout"); logout_mock.expects("logout").once(); - var controller = controllerFor('user-dropdown'); + var controller = this.subject(); controller.send("logout"); logout_mock.verify(); @@ -18,9 +12,10 @@ test("logout action logs out the current user", function () { test("showAdminLinks", function() { var currentUserStub = Ember.Object.create(); - this.stub(Discourse.User, "current").returns(currentUserStub); + sandbox.stub(Discourse.User, "current").returns(currentUserStub); currentUserStub.set("staff", true); + var controller = this.subject(); equal(controller.get("showAdminLinks"), true, "is true when current user is a staff member"); currentUserStub.set("staff", false); diff --git a/test/javascripts/fixtures/user_fixtures.js b/test/javascripts/fixtures/user_fixtures.js index 21c3b953c..b440dabd8 100644 --- a/test/javascripts/fixtures/user_fixtures.js +++ b/test/javascripts/fixtures/user_fixtures.js @@ -6,4 +6,4 @@ Discourse.URL_FIXTURES["/user_actions.json?offset=0&username=eviltrout&filter=5" Discourse.URL_FIXTURES["/user_actions.json?offset=0&username=eviltrout&filter=6,7,9"] = {"user_actions":[{"action_type":7,"created_at":"2014-01-16T14:13:05Z","excerpt":"So again, \n\nWhat is the problem?\n\nI need to check user_trust_level , i get the 'username' from a form via ajax, i need to check what level he is on discourse \n\nAlso, if possible, i would like to get other details as well, like email address etc. \n\nI took a look at : <a href='https://github.com/discourse/discourse_api' rel='nofollow'>https://github.com/discourse/dis…</a>","avatar_template":"//www.gravatar.com/avatar/bdab7e61b3191e483492fd680f563fed.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/bdab7e61b3191e483492fd680f563fed.png?s={size}&r=pg&d=identicon","slug":"how-to-check-the-user-level-via-ajax","topic_id":11993,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":1,"reply_to_post_number":null,"username":"Abhishek_Gupta","name":"Abhishek Gupta","user_id":8021,"acting_username":"Abhishek_Gupta","acting_name":"Abhishek Gupta","acting_user_id":8021,"title":"How to check the user level via ajax?","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":6,"created_at":"2014-01-15T12:22:12Z","excerpt":"OK - i see what you mean. From the piwik code I should add: \n\n_paq.push(["setDocumentTitle", document.domain + "/" + document.title]);\n\n? \n\nUnfortunately I have had to give up on Piwik for now because I have switched the forum to SSL on a free cert and have used up the free subdomain for the forum. …","avatar_template":"//localhost:3000/uploads/default/avatars/2a8/a3c/8fddcac642/{size}.jpg","acting_avatar_template":"//localhost:3000/uploads/default/avatars/2a8/a3c/8fddcac642/{size}.jpg","slug":"support-for-piwik-analytics-as-an-alternative-to-google-analytics","topic_id":7512,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":26,"reply_to_post_number":25,"username":"citkane","name":"Michael Jonker","user_id":7604,"acting_username":"citkane","acting_name":"Michael Jonker","acting_user_id":7604,"title":"Support for Piwik Analytics as an alternative to Google Analytics","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":7,"created_at":"2014-01-15T11:16:36Z","excerpt":"<a class='mention' href='/users/eviltrout'>@eviltrout</a> recently added support for multiple API keys [wink] \n\n<a href='//meta.discourse.org/uploads/default/2905/4c8decfac1518ff6.png' target='_blank'>[]</a>","avatar_template":"//www.gravatar.com/avatar/b7797beb47cfb7aa0fe60d09604aaa09.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/b7797beb47cfb7aa0fe60d09604aaa09.png?s={size}&r=pg&d=identicon","slug":"allow-for-multiple-api-keys","topic_id":7444,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":3,"reply_to_post_number":null,"username":"zogstrip","name":"Régis Hanol","user_id":1995,"acting_username":"zogstrip","acting_name":"Régis Hanol","acting_user_id":1995,"title":"Allow for multiple API Keys","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":7,"created_at":"2014-01-15T10:58:46Z","excerpt":"<a class='mention' href='/users/eviltrout'>@eviltrout</a> added a tooltip when you click on the user's avatar which allows you to show the posts made by that user \n\n[image]","avatar_template":"//www.gravatar.com/avatar/b7797beb47cfb7aa0fe60d09604aaa09.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/b7797beb47cfb7aa0fe60d09604aaa09.png?s={size}&r=pg&d=identicon","slug":"to-group-posts-by-a-user","topic_id":7412,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":4,"reply_to_post_number":3,"username":"zogstrip","name":"Régis Hanol","user_id":1995,"acting_username":"zogstrip","acting_name":"Régis Hanol","acting_user_id":1995,"title":"To group posts by a user","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":7,"created_at":"2014-01-15T10:36:15Z","excerpt":"<a class='mention' href='/users/eviltrout'>@eviltrout</a> implemented per-user API key a while ago [wink] \n\n <a href='//meta-discourse.r.worldssl.net/uploads/default/2905/4c8decfac1518ff6.png' class='lightbox' title='Topics_-_Discourse_Meta-5.png'>[image]\nTopics_-_Discourse_Meta-5.png884x339 29.6 KB\n</a>","avatar_template":"//www.gravatar.com/avatar/b7797beb47cfb7aa0fe60d09604aaa09.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/b7797beb47cfb7aa0fe60d09604aaa09.png?s={size}&r=pg&d=identicon","slug":"auth-using-rest-api","topic_id":5937,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":3,"reply_to_post_number":2,"username":"zogstrip","name":"Régis Hanol","user_id":1995,"acting_username":"zogstrip","acting_name":"Régis Hanol","acting_user_id":1995,"title":"Auth using REST API?","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":7,"created_at":"2014-01-15T09:55:17Z","excerpt":"<a class='mention' href='/users/eviltrout'>@eviltrout</a> has recently introduced this feature and has even blogged about it: \n\n \n \n \n <a href='http://eviltrout.com/2014/01/04/hiding-offscreen-ember.html' class='track-link' target='_blank'>\n eviltrout.com\n </a>\n \n \n \n \n <a href='http://eviltrout.com/2014/01/04/hiding-offscreen-ember.html' target='_blank'>Hiding Offscreen Content in Ember.js - Evil Trout's Blog</a>","avatar_template":"//www.gravatar.com/avatar/b7797beb47cfb7aa0fe60d09604aaa09.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/b7797beb47cfb7aa0fe60d09604aaa09.png?s={size}&r=pg&d=identicon","slug":"infinite-scrolling-reusing-dom-nodes","topic_id":5186,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":3,"reply_to_post_number":null,"username":"zogstrip","name":"Régis Hanol","user_id":1995,"acting_username":"zogstrip","acting_name":"Régis Hanol","acting_user_id":1995,"title":"Infinite scrolling: Reusing DOM nodes","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":6,"created_at":"2014-01-14T21:43:28Z","excerpt":"Thanks for your help <a class='mention' href='/users/eviltrout'>@eviltrout</a>! I will consider making that change and sending a pull request. I may not get to it for a while. \n\nI am embedding Discourse on another site and it is mostly going well. I have indeed been using your blog for inspiration.","avatar_template":"//www.gravatar.com/avatar/9cfd2536afac32d209335b092094c12c.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/9cfd2536afac32d209335b092094c12c.png?s={size}&r=pg&d=identicon","slug":"get-current-user-information-via-json","topic_id":11959,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":3,"reply_to_post_number":2,"username":"znation","name":"znation","user_id":8163,"acting_username":"znation","acting_name":"znation","acting_user_id":8163,"title":"Get current user information via JSON","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":6,"created_at":"2014-01-14T18:37:05Z","excerpt":"I'd be glad to write a pull request to take use there. Is there a specific part of their documentation you have in mind?","avatar_template":"//www.gravatar.com/avatar/035d12bad251759d8fbc9fb10574d1f6.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/035d12bad251759d8fbc9fb10574d1f6.png?s={size}&r=pg&d=identicon","slug":"how-far-to-take-user-documentation","topic_id":11943,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":3,"reply_to_post_number":2,"username":"watchmanmonitor","name":"Watchman Monitoring","user_id":8085,"acting_username":"watchmanmonitor","acting_name":"Watchman Monitoring","acting_user_id":8085,"title":"How far to take user documentation?","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":6,"created_at":"2014-01-14T16:04:28Z","excerpt":"Thanks <a class='mention' href='/users/eviltrout'>@eviltrout</a> , the code in the 'bottom of pages' now reads: \n\n<script type="text/javascript">\nDiscourse.PageTracker.current().on('change', function() {\n console.log('tracked!')\n _paq.push(['trackPageView']);\n});\n</script>\n\nThe console is logging 'tracked!' and piwik is logging for each page c…","avatar_template":"//localhost:3000/uploads/default/avatars/2a8/a3c/8fddcac642/{size}.jpg","acting_avatar_template":"//localhost:3000/uploads/default/avatars/2a8/a3c/8fddcac642/{size}.jpg","slug":"support-for-piwik-analytics-as-an-alternative-to-google-analytics","topic_id":7512,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":23,"reply_to_post_number":22,"username":"citkane","name":"Michael Jonker","user_id":7604,"acting_username":"citkane","acting_name":"Michael Jonker","acting_user_id":7604,"title":"Support for Piwik Analytics as an alternative to Google Analytics","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":7,"created_at":"2014-01-14T00:21:26Z","excerpt":"In <a href='https://github.com/discourse/discourse/pull/1821' rel='nofollow'>pull request 1821</a>, <a class='mention' href='/users/eviltrout'>@eviltrout</a> asked: \n\n "About rails s: I wouldn't be against adding it but at what point do we stop holding their hand and expect them to know how rails works? I'm sure rails documentation could do a better job than us. Actually maybe we should just link to that? \n\nWhat point to …","avatar_template":"//www.gravatar.com/avatar/035d12bad251759d8fbc9fb10574d1f6.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/035d12bad251759d8fbc9fb10574d1f6.png?s={size}&r=pg&d=identicon","slug":"how-far-to-take-user-documentation","topic_id":11943,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":1,"reply_to_post_number":null,"username":"watchmanmonitor","name":"Watchman Monitoring","user_id":8085,"acting_username":"watchmanmonitor","acting_name":"Watchman Monitoring","acting_user_id":8085,"title":"How far to take user documentation?","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":6,"created_at":"2014-01-13T21:58:28Z","excerpt":"It looks uneeded, but you need to review a fair amount of code to confirm it is not needed. \n\nI am going to keep it for now cause its safer under some weird edge conditions.","avatar_template":"//www.gravatar.com/avatar/3dcae8378d46c244172a115c28ca49ce.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/3dcae8378d46c244172a115c28ca49ce.png?s={size}&r=pg&d=identicon","slug":"ruby-question-about-use-of-klass-self-in-the-site-customization-rb","topic_id":11889,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":3,"reply_to_post_number":2,"username":"sam","name":"Sam Saffron","user_id":1,"acting_username":"sam","acting_name":"Sam Saffron","acting_user_id":1,"title":"Ruby question about use of klass=self in the site_customization.rb","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":6,"created_at":"2014-01-13T21:10:57Z","excerpt":"Having a look, the fix is a bit scary imho, we should fix the root issue.","avatar_template":"//www.gravatar.com/avatar/3dcae8378d46c244172a115c28ca49ce.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/3dcae8378d46c244172a115c28ca49ce.png?s={size}&r=pg&d=identicon","slug":"error-after-update-to-0-9-8-1","topic_id":11903,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":11,"reply_to_post_number":10,"username":"sam","name":"Sam Saffron","user_id":1,"acting_username":"sam","acting_name":"Sam Saffron","acting_user_id":1,"title":"Error after update to 0.9.8.1","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":7,"created_at":"2014-01-13T16:41:31Z","excerpt":"I'd love to see API support. <a class='mention' href='/users/sam'>@sam</a> and <a class='mention' href='/users/eviltrout'>@eviltrout</a>, I can facilitate an intro to the piwik guys if you want—I've written about them before and they're typically super-responsive. Because I know you guys are totally hunting for new stuff to do [wink]","avatar_template":"//localhost:3000/uploads/default/avatars/95a/06d/c337428568/{size}.png","acting_avatar_template":"//localhost:3000/uploads/default/avatars/95a/06d/c337428568/{size}.png","slug":"support-for-piwik-analytics-as-an-alternative-to-google-analytics","topic_id":7512,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":20,"reply_to_post_number":null,"username":"Lee_Ars","name":"Lee_Ars","user_id":4457,"acting_username":"Lee_Ars","acting_name":"Lee_Ars","acting_user_id":4457,"title":"Support for Piwik Analytics as an alternative to Google Analytics","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":7,"created_at":"2014-01-13T06:27:26Z","excerpt":"Can this be archived <a class='mention' href='/users/eviltrout'>@eviltrout</a>?","avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","slug":"search-not-working-for-staff-users","topic_id":11371,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":13,"reply_to_post_number":null,"username":"codinghorror","name":"Jeff Atwood","user_id":32,"acting_username":"codinghorror","acting_name":"Jeff Atwood","acting_user_id":32,"title":"Search not working for Staff users","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":7,"created_at":"2014-01-13T05:32:46Z","excerpt":"When you navigate to another topic using the "suggested topics" area we are not registering a page view with Google. \n\n<a class='mention' href='/users/eviltrout'>@eviltrout</a> perhaps we should do this from discourse location instead of application controller?","avatar_template":"//www.gravatar.com/avatar/3dcae8378d46c244172a115c28ca49ce.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/3dcae8378d46c244172a115c28ca49ce.png?s={size}&r=pg&d=identicon","slug":"google-analytics-is-not-registering-page-views","topic_id":11914,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":1,"reply_to_post_number":null,"username":"sam","name":"Sam Saffron","user_id":1,"acting_username":"sam","acting_name":"Sam Saffron","acting_user_id":1,"title":"Google analytics is not registering page views","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":7,"created_at":"2014-01-13T02:50:25Z","excerpt":"<a class='mention' href='/users/eviltrout'>@eviltrout</a> any ideas here, the code seems correct","avatar_template":"//www.gravatar.com/avatar/3dcae8378d46c244172a115c28ca49ce.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/3dcae8378d46c244172a115c28ca49ce.png?s={size}&r=pg&d=identicon","slug":"support-for-piwik-analytics-as-an-alternative-to-google-analytics","topic_id":7512,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":17,"reply_to_post_number":16,"username":"sam","name":"Sam Saffron","user_id":1,"acting_username":"sam","acting_name":"Sam Saffron","acting_user_id":1,"title":"Support for Piwik Analytics as an alternative to Google Analytics","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":7,"created_at":"2014-01-12T22:31:35Z","excerpt":"This is an interesting approach an an interesting feature. <a class='mention' href='/users/eviltrout'>@eviltrout</a> your thoughts. Essentially allows us to have notifications cross tabs.","avatar_template":"//www.gravatar.com/avatar/3dcae8378d46c244172a115c28ca49ce.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/3dcae8378d46c244172a115c28ca49ce.png?s={size}&r=pg&d=identicon","slug":"focus-events-track-which-window-is-the-last-active-instance-of-a-forum-edit","topic_id":11872,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":4,"reply_to_post_number":1,"username":"sam","name":"Sam Saffron","user_id":1,"acting_username":"sam","acting_name":"Sam Saffron","acting_user_id":1,"title":"Focus events: Track which window is the last active instance of a forum Edit","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":7,"created_at":"2014-01-12T18:01:04Z","excerpt":"This was the link \n\n<a href='https://github.com/metricfu/metric_fu/blob/b1bf8feb921916fc265f041efa3157a6a6530a9b/lib/metric_fu/logging/mf_debugger.rb#L24' rel='nofollow'>metric_fu</a> \n\n[metric_fu](https://github.com/metricfu/metric_fu/blob/b1bf8feb921916fc265f041efa3157a6a6530a9b/lib/metric_fu/logging/mf_debugger.rb#L24)\n\nSeems to work fine now that <a class='mention' href='/users/eviltrout'>@eviltrout</a> worked so hard to get us MDTest 1.1 compliant.","avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","slug":"underscores-in-linked-text-can-cause-markdown-bug","topic_id":10848,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":3,"reply_to_post_number":null,"username":"codinghorror","name":"Jeff Atwood","user_id":32,"acting_username":"codinghorror","acting_name":"Jeff Atwood","acting_user_id":32,"title":"Underscores in linked text can cause markdown bug","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":6,"created_at":"2014-01-12T04:14:06Z","excerpt":"Awesome plugin, but doesn't seem to work out of the box with images \n\n<a href='https://github.com/discourse/discourse-spoiler-alert/issues/2' class='onebox' target='_blank' rel='nofollow'>https://github.com/discourse/discourse-spoiler-alert/issues/2</a>","avatar_template":"//localhost:3000/uploads/default/avatars/276/f19/3826efe463/{size}.jpg","acting_avatar_template":"//localhost:3000/uploads/default/avatars/276/f19/3826efe463/{size}.jpg","slug":"brand-new-plugin-interface","topic_id":8793,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":64,"reply_to_post_number":44,"username":"xrvk","name":"Eero Heikkinen","user_id":8068,"acting_username":"xrvk","acting_name":"Eero Heikkinen","acting_user_id":8068,"title":"Brand new plugin interface","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":7,"created_at":"2014-01-11T23:36:11Z","excerpt":"A few things, \n\n<a class='mention' href='/users/eviltrout'>@eviltrout</a> myself and many others have discourse_docker hosted on digital ocean, my user cpu is usually around 2% I have plenty of capacity. \n\nI know that stonehearth and other larger scale discourse work on digital ocean fine. Officially we strongly recommend a 2GB instance, thoug…","avatar_template":"//www.gravatar.com/avatar/3dcae8378d46c244172a115c28ca49ce.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/3dcae8378d46c244172a115c28ca49ce.png?s={size}&r=pg&d=identicon","slug":"performance-issue-on-digital-ocean-with-discourse-docker","topic_id":11895,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":2,"reply_to_post_number":null,"username":"sam","name":"Sam Saffron","user_id":1,"acting_username":"sam","acting_name":"Sam Saffron","acting_user_id":1,"title":"Performance issue on Digital Ocean with discourse_docker","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":7,"created_at":"2014-01-11T00:58:23Z","excerpt":"Confirmed on try.discourse.org, this is still an issue. \n\n<a class='mention' href='/users/eviltrout'>@eviltrout</a> can you add that to your list -- unless you are a staff member you should not be able to delete (your own) posts from an archived topic.","avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","slug":"archived-discussions-still-allow-posts-to-be-deleted","topic_id":6479,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":3,"reply_to_post_number":null,"username":"codinghorror","name":"Jeff Atwood","user_id":32,"acting_username":"codinghorror","acting_name":"Jeff Atwood","acting_user_id":32,"title":"Archived discussions still allow posts to be deleted","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":7,"created_at":"2014-01-11T00:35:38Z","excerpt":"Agree, <a class='mention' href='/users/eviltrout'>@eviltrout</a> can you make sure the usercard is using the same logic as the user page in displaying profile info?","avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","slug":"usercard-does-not-resize-for-obnoxiously-large-images","topic_id":11007,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":5,"reply_to_post_number":4,"username":"codinghorror","name":"Jeff Atwood","user_id":32,"acting_username":"codinghorror","acting_name":"Jeff Atwood","acting_user_id":32,"title":"Usercard does not resize for obnoxiously large images","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":7,"created_at":"2014-01-11T00:34:06Z","excerpt":"<a class='mention' href='/users/eviltrout'>@eviltrout</a> can you make sure the "import post" button is suppressed on the user page when editing "about me"? \n\n(I agree it is like a "lose all my work" button on that page if you happen to press it..) \n\nThen I can archive this.","avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","slug":"quote-post-button-should-be-disabled-or-raise-an-error-when-creating-a-new-topic","topic_id":834,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":5,"reply_to_post_number":4,"username":"codinghorror","name":"Jeff Atwood","user_id":32,"acting_username":"codinghorror","acting_name":"Jeff Atwood","acting_user_id":32,"title":"\"Quote Post\" button should be disabled or raise an error when creating a new topic","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":7,"created_at":"2014-01-10T21:00:11Z","excerpt":">\n\nLooks good now. Thanks for these fixes <a class='mention' href='/users/eviltrout'>@eviltrout</a>, we (and markdown-js) are now MDTest 1.1 compliant!","avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","slug":"text-editor-issue-with-the-code-block","topic_id":10050,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":5,"reply_to_post_number":null,"username":"codinghorror","name":"Jeff Atwood","user_id":32,"acting_username":"codinghorror","acting_name":"Jeff Atwood","acting_user_id":32,"title":"Text Editor issue with the code block","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":6,"created_at":"2014-01-10T17:02:35Z","excerpt":"Fixed [smile] \n\ntop - 12:02:00 up 12 days, 2:16, 1 user, load average: 0.28, 0.92, 0.97\nTasks: 115 total, 1 running, 114 sleeping, 0 stopped, 0 zombie\nCpu0 : 0.7%us, 0.3%sy, 0.0%ni, 99.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st\nCpu1 : 0.7%us, 0.3%sy, 0.0%ni, 99.0%id, 0.0%wa, 0.0%hi,…","avatar_template":"//localhost:3000/uploads/default/avatars/886/ea8/e533d87fd9/{size}.png","acting_avatar_template":"//localhost:3000/uploads/default/avatars/886/ea8/e533d87fd9/{size}.png","slug":"sidekiq-cpu-load-since-latest-release","topic_id":9515,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":23,"reply_to_post_number":22,"username":"michaeld","name":"Michael","user_id":6548,"acting_username":"michaeld","acting_name":"Michael","acting_user_id":6548,"title":"Sidekiq CPU load since latest release","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":7,"created_at":"2014-01-10T06:37:23Z","excerpt":"I think <a class='mention' href='/users/eviltrout'>@eviltrout</a> fixed this in his last round of email digest improvements? Can you confirm Robin?","avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","slug":"users-linked-in-replies-dont-link-properly-in-email-body","topic_id":6613,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":3,"reply_to_post_number":null,"username":"codinghorror","name":"Jeff Atwood","user_id":32,"acting_username":"codinghorror","acting_name":"Jeff Atwood","acting_user_id":32,"title":"Users linked in replies don't link properly in email body","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":7,"created_at":"2014-01-10T06:32:33Z","excerpt":"Should be fixed with <a class='mention' href='/users/eviltrout'>@eviltrout</a>'s recent topic stream revamp.","avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","slug":"toggle-topic-details-carries-over","topic_id":10522,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":3,"reply_to_post_number":null,"username":"codinghorror","name":"Jeff Atwood","user_id":32,"acting_username":"codinghorror","acting_name":"Jeff Atwood","acting_user_id":32,"title":"Toggle topic details carries over","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":7,"created_at":"2014-01-10T06:13:30Z","excerpt":"I believe <a class='mention' href='/users/eviltrout'>@eviltrout</a> resolved all the bugs with too-large progress counter numbers.","avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","slug":"wrong-topic-counter-just-after-replying","topic_id":6324,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":22,"reply_to_post_number":null,"username":"codinghorror","name":"Jeff Atwood","user_id":32,"acting_username":"codinghorror","acting_name":"Jeff Atwood","acting_user_id":32,"title":"Wrong Topic counter just after replying","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":7,"created_at":"2014-01-10T05:39:37Z","excerpt":"I believe this is effectively complete with <a class='mention' href='/users/eviltrout'>@eviltrout</a>'s massive refactor of the topic stream recently to support topics with 1k+ replies, isn't it?","avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","slug":"smarter-scroll-handling","topic_id":7238,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":2,"reply_to_post_number":null,"username":"codinghorror","name":"Jeff Atwood","user_id":32,"acting_username":"codinghorror","acting_name":"Jeff Atwood","acting_user_id":32,"title":"Smarter scroll handling","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":7,"created_at":"2014-01-09T11:13:56Z","excerpt":"I think I have seen this in IE10 and IE11 as well. It is odd how often quirks from Firefox also appear in IE. <a class='mention' href='/users/eviltrout'>@eviltrout</a> can you take a look?","avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","slug":"scrolling-up-jumps-to-top-of-page","topic_id":11847,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":2,"reply_to_post_number":null,"username":"codinghorror","name":"Jeff Atwood","user_id":32,"acting_username":"codinghorror","acting_name":"Jeff Atwood","acting_user_id":32,"title":"Scrolling up jumps to top of page","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":7,"created_at":"2014-01-07T00:38:43Z","excerpt":"Excellent, thank you, for the record I did all the work and <a class='mention' href='/users/eviltrout'>@eviltrout</a> <a class='mention' href='/users/sam'>@sam</a> <a class='mention' href='/users/neil'>@neil</a> <a class='mention' href='/users/zogstrip'>@zogstrip</a> did virtually nothing. I only list them here to be polite. \n\nOne way you can help the project: spread the word about Discourse, so more people may discover us and know there is a non-terrible free forum optio…","avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","slug":"awesomenesssss-it-is","topic_id":11462,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":4,"reply_to_post_number":null,"username":"codinghorror","name":"Jeff Atwood","user_id":32,"acting_username":"codinghorror","acting_name":"Jeff Atwood","acting_user_id":32,"title":"Awesomenesssss it is","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":6,"created_at":"2014-01-06T16:26:53Z","excerpt":"Like when I want to achieve something similar to the <a href='http://meta.discourse.org/t/how-would-you-migrate-the-wordpress-org-forum-to-discourse/9797'>WP plugin forums</a> or <a href='http://meta.discourse.org/t/can-discourse-do-what-ost-io-does/11737'>ost.io</a>. \n\nI suppose I'm really talking about all posts in a category, yeah. But just the latest ones with a "Read more" type link to the full category purely within Discourse would be fine to.","avatar_template":"//www.gravatar.com/avatar/69fda0df8b4878fb6a18deffa972d26a.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/69fda0df8b4878fb6a18deffa972d26a.png?s={size}&r=pg&d=identicon","slug":"discourse-plugin-for-static-site-generators-like-jekyll-or-octopress","topic_id":7965,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":97,"reply_to_post_number":96,"username":"erlend_sh","name":"Erlend Sogge Heggen","user_id":5351,"acting_username":"erlend_sh","acting_name":"Erlend Sogge Heggen","acting_user_id":5351,"title":"Discourse plugin for static site generators like Jekyll or Octopress","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":7,"created_at":"2014-01-03T21:35:39Z","excerpt":"We should probably pull this. It was experimental and /top does what it was supposed to do for the most part. We also have category mute/watch prefs coming. \n\n<a class='mention' href='/users/eviltrout'>@eviltrout</a> I say we pull the old poll topic type stuff (as well as todo topic type) and hotness stuff.","avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","slug":"what-is-category-hotness","topic_id":11734,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":3,"reply_to_post_number":null,"username":"codinghorror","name":"Jeff Atwood","user_id":32,"acting_username":"codinghorror","acting_name":"Jeff Atwood","acting_user_id":32,"title":"What is category hotness?","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":6,"created_at":"2014-01-03T18:39:50Z","excerpt":"This is awesome! Thanks! [smile]","avatar_template":"//www.gravatar.com/avatar/82c793022ec1bce6ea7573bc27b2340b.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/82c793022ec1bce6ea7573bc27b2340b.png?s={size}&r=pg&d=identicon","slug":"discourse-plugin-for-static-site-generators-like-jekyll-or-octopress","topic_id":7965,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":92,"reply_to_post_number":91,"username":"PabloC","name":"Pablo Corral","user_id":2291,"acting_username":"PabloC","acting_name":"Pablo Corral","acting_user_id":2291,"title":"Discourse plugin for static site generators like Jekyll or Octopress","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":6,"created_at":"2014-01-02T21:46:14Z","excerpt":"Wrong link, this is the correct commit: \n\n<a href='https://github.com/discourse/discourse/commit/f14506031520a3b8ab83aa25ee576d0c1b515ff9' target='_blank'>https://github.com/discourse/discourse/commit/f14506031520a3b8ab83aa25ee576d0c1b515ff9</a>","avatar_template":"//www.gravatar.com/avatar/5120fc4e345db0d1a964888272073819.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/5120fc4e345db0d1a964888272073819.png?s={size}&r=pg&d=identicon","slug":"what-is-the-point-of-limiting-new-users-to-three-replies-per-topic","topic_id":11696,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":14,"reply_to_post_number":13,"username":"riking","name":"Kane York","user_id":6626,"acting_username":"riking","acting_name":"Kane York","acting_user_id":6626,"title":"What is the point of limiting new users to three replies per topic?","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":6,"created_at":"2014-01-02T19:58:51Z","excerpt":"Oh, cool! I wasn't sure what the path was to add comments for just random pages. I didn't think it'd actually crawl forward... that's really useful. \n\nForever ago I said that I'd adapt the little script I wrote to work with ghost, but with this new feature it's actually very easy, and not needed! Th…","avatar_template":"//localhost:3000/uploads/default/avatars/527/614/d16e1504d9/{size}.jpg","acting_avatar_template":"//localhost:3000/uploads/default/avatars/527/614/d16e1504d9/{size}.jpg","slug":"discourse-plugin-for-static-site-generators-like-jekyll-or-octopress","topic_id":7965,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":90,"reply_to_post_number":88,"username":"trident","name":"Ben T","user_id":5707,"acting_username":"trident","acting_name":"Ben T","acting_user_id":5707,"title":"Discourse plugin for static site generators like Jekyll or Octopress","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":6,"created_at":"2014-01-02T18:39:25Z","excerpt":"I was trying this new feature out, and it totally improves upon what was here in lots of ways and has more official css to boot. It's very, very cool! \n\nI think it would be useful to be able to manually associate threads to the embed url; so single page sites do not have to create a feed just to ad…","avatar_template":"//localhost:3000/uploads/default/avatars/527/614/d16e1504d9/{size}.jpg","acting_avatar_template":"//localhost:3000/uploads/default/avatars/527/614/d16e1504d9/{size}.jpg","slug":"discourse-plugin-for-static-site-generators-like-jekyll-or-octopress","topic_id":7965,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":87,"reply_to_post_number":85,"username":"trident","name":"Ben T","user_id":5707,"acting_username":"trident","acting_name":"Ben T","acting_user_id":5707,"title":"Discourse plugin for static site generators like Jekyll or Octopress","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":7,"created_at":"2014-01-02T06:24:12Z","excerpt":"If you don't read the yellow box -- which shows up even before you begin typing in the screenshot shown above -- then we don't want you as a user. What do you want the software to do, drive to the person's house and have a face to face intervention with them? \n\nThe "sorry you can't reply any more ti…","avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","slug":"what-is-the-point-of-limiting-new-users-to-three-replies-per-topic","topic_id":11696,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":9,"reply_to_post_number":8,"username":"codinghorror","name":"Jeff Atwood","user_id":32,"acting_username":"codinghorror","acting_name":"Jeff Atwood","acting_user_id":32,"title":"What is the point of limiting new users to three replies per topic?","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":7,"created_at":"2014-01-02T06:05:07Z","excerpt":"The main UI difference is: \n\n\nIf you click anywhere on the top (even where mouse is not cursor or on an A) it will take you to the top.\nWhen it takes you to the top it "scrolls" with an animation. \nWe used to scroll with an animation <a class='mention' href='/users/eviltrout'>@eviltrout</a> any way that could return?","avatar_template":"//www.gravatar.com/avatar/3dcae8378d46c244172a115c28ca49ce.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/3dcae8378d46c244172a115c28ca49ce.png?s={size}&r=pg&d=identicon","slug":"click-top-bar-to-scroll-top","topic_id":11655,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":8,"reply_to_post_number":7,"username":"sam","name":"Sam Saffron","user_id":1,"acting_username":"sam","acting_name":"Sam Saffron","acting_user_id":1,"title":"Click top bar to scroll top","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":7,"created_at":"2014-01-01T19:14:37Z","excerpt":"You bring up a good point -- for topics you yourself have created, we should probably relax this requirement a bit or even remove it. \n\nWhat do you think <a class='mention' href='/users/eviltrout'>@eviltrout</a>?","avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","slug":"what-is-the-point-of-limiting-new-users-to-three-replies-per-topic","topic_id":11696,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":3,"reply_to_post_number":null,"username":"codinghorror","name":"Jeff Atwood","user_id":32,"acting_username":"codinghorror","acting_name":"Jeff Atwood","acting_user_id":32,"title":"What is the point of limiting new users to three replies per topic?","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":7,"created_at":"2013-12-31T05:16:17Z","excerpt":"Are we any closer on this <a class='mention' href='/users/eviltrout'>@eviltrout</a>? This, along with whitelisting of onebox URLs in the /admin UI feel like important features to me.","avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","slug":"setting-timeout-times-for-oneboxes","topic_id":11648,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":5,"reply_to_post_number":null,"username":"codinghorror","name":"Jeff Atwood","user_id":32,"acting_username":"codinghorror","acting_name":"Jeff Atwood","acting_user_id":32,"title":"Setting timeout times for oneboxes","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":6,"created_at":"2013-12-31T00:10:38Z","excerpt":"Interesting to know, not sure how you managed though.","avatar_template":"//localhost:3000/uploads/default/avatars/42c/88a/f92e28ef15/{size}.png","acting_avatar_template":"//localhost:3000/uploads/default/avatars/42c/88a/f92e28ef15/{size}.png","slug":"limiting-number-of-posts-on-a-new-users-first-day","topic_id":11667,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":7,"reply_to_post_number":6,"username":"Roach","name":"Martin","user_id":8045,"acting_username":"Roach","acting_name":"Martin","acting_user_id":8045,"title":"Limiting number of posts on a new user's first day","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":6,"created_at":"2013-12-30T23:34:09Z","excerpt":"<a href='//meta-discourse.r.worldssl.net/uploads/default/2524/46fcc902258a1c8f.png' class='lightbox' title='Pasted image'>[image]\nPasted image1057x796 71.3 KB\n</a>\n\nThis is buggy <a class='mention' href='/users/roach'>@Roach</a> is no longer a new user, yet can not post.","avatar_template":"//www.gravatar.com/avatar/3dcae8378d46c244172a115c28ca49ce.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/3dcae8378d46c244172a115c28ca49ce.png?s={size}&r=pg&d=identicon","slug":"limiting-number-of-posts-on-a-new-users-first-day","topic_id":11667,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":4,"reply_to_post_number":3,"username":"sam","name":"Sam Saffron","user_id":1,"acting_username":"sam","acting_name":"Sam Saffron","acting_user_id":1,"title":"Limiting number of posts on a new user's first day","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":7,"created_at":"2013-12-30T02:05:50Z","excerpt":"Ouch afaik, this has been implemented in <a href='https://github.com/dysania/onebox' rel='nofollow'>https://github.com/dysania/onebox</a> \n\nWe are waiting on <a class='mention' href='/users/eviltrout'>@eviltrout</a> <a class='mention' href='/users/vykster'>@vykster</a> <a class='mention' href='/users/krainboltgreene'>@krainboltgreene</a> and <a class='mention' href='/users/jzeta'>@jzeta</a> to yank all the onebox code out and depend on the onebox gem. \n\nAny way you can shift your efforts to integrating the gem or ensuring it really does work a…","avatar_template":"//www.gravatar.com/avatar/3dcae8378d46c244172a115c28ca49ce.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/3dcae8378d46c244172a115c28ca49ce.png?s={size}&r=pg&d=identicon","slug":"setting-timeout-times-for-oneboxes","topic_id":11648,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":2,"reply_to_post_number":null,"username":"sam","name":"Sam Saffron","user_id":1,"acting_username":"sam","acting_name":"Sam Saffron","acting_user_id":1,"title":"Setting timeout times for oneboxes","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":7,"created_at":"2013-12-30T00:08:41Z","excerpt":"<a class='mention' href='/users/codinghorror'>@codinghorror</a> <a class='mention' href='/users/eviltrout'>@eviltrout</a> <a class='mention' href='/users/awesomerobot'>@awesomerobot</a> I feel having one UI for "bunch of categories" would be beneficial, at the moment we have: \n\n [image] \n\nand \n\n[image] \n\nI feel the "humberger" style (with possible tweaks) should be used in the cat drop down \n\n\nHamburger style has more information (topic count…","avatar_template":"//www.gravatar.com/avatar/3dcae8378d46c244172a115c28ca49ce.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/3dcae8378d46c244172a115c28ca49ce.png?s={size}&r=pg&d=identicon","slug":"category-selection-menu-design-suggestion","topic_id":11619,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":9,"reply_to_post_number":8,"username":"sam","name":"Sam Saffron","user_id":1,"acting_username":"sam","acting_name":"Sam Saffron","acting_user_id":1,"title":"Category selection menu design suggestion","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":7,"created_at":"2013-12-29T10:08:11Z","excerpt":"Thanks heaps, seen this here as well, its clearly a bug, will have a look tomorrow. \n\ncc <a class='mention' href='/users/eviltrout'>@eviltrout</a>","avatar_template":"//www.gravatar.com/avatar/3dcae8378d46c244172a115c28ca49ce.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/3dcae8378d46c244172a115c28ca49ce.png?s={size}&r=pg&d=identicon","slug":"reply-by-email-failed-on-non-english-language","topic_id":11638,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":2,"reply_to_post_number":null,"username":"sam","name":"Sam Saffron","user_id":1,"acting_username":"sam","acting_name":"Sam Saffron","acting_user_id":1,"title":"Reply by email failed on non-english language","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":6,"created_at":"2013-12-23T22:26:17Z","excerpt":"Admins are different though, they can change settings that could easily break the forum for everyone, and have access to some pretty technical forum settings. So I don't think showing them page load times is so utterly beyond the pale. \n\nPlain mods should not see it though.","avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","slug":"performance-times","topic_id":11567,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":8,"reply_to_post_number":7,"username":"codinghorror","name":"Jeff Atwood","user_id":32,"acting_username":"codinghorror","acting_name":"Jeff Atwood","acting_user_id":32,"title":"Performance Times","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":6,"created_at":"2013-12-23T22:15:51Z","excerpt":"I believe performance is a core value, so I do not support moving that into a plugin. \n\nMaybe we should make it so the perf times only show for admins and not mere moderators though, that would help.","avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","slug":"performance-times","topic_id":11567,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":6,"reply_to_post_number":5,"username":"codinghorror","name":"Jeff Atwood","user_id":32,"acting_username":"codinghorror","acting_name":"Jeff Atwood","acting_user_id":32,"title":"Performance Times","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":6,"created_at":"2013-12-23T19:18:44Z","excerpt":"A bit early to turn it off now imo, but I will be way more open to it when we ship our first stable release.","avatar_template":"//www.gravatar.com/avatar/3dcae8378d46c244172a115c28ca49ce.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/3dcae8378d46c244172a115c28ca49ce.png?s={size}&r=pg&d=identicon","slug":"performance-times","topic_id":11567,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":4,"reply_to_post_number":2,"username":"sam","name":"Sam Saffron","user_id":1,"acting_username":"sam","acting_name":"Sam Saffron","acting_user_id":1,"title":"Performance Times","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":7,"created_at":"2013-12-20T19:24:16Z","excerpt":"I can repro this on the "what is the most awesome plugin" topic, in portrait mode on my iPad with iOS 7.0.4 too. Stops at post 19. <a class='mention' href='/users/eviltrout'>@eviltrout</a> can you have a look?","avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","slug":"ipad-portrait-mode-scrolling-stops-at-the-19th-post","topic_id":11524,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":4,"reply_to_post_number":null,"username":"codinghorror","name":"Jeff Atwood","user_id":32,"acting_username":"codinghorror","acting_name":"Jeff Atwood","acting_user_id":32,"title":"iPad, portrait mode: scrolling stops at the 19th post","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":7,"created_at":"2013-12-20T09:13:50Z","excerpt":"I created a new user on <a href='http://try.discourse.org'>http://try.discourse.org</a> and set this user to trust level zero (try defaults to trust level 1 so people can exercise a bit more stuff), then I posted 3 times in the same topic: \n\n[image] \n\nIf I ignore the warning and try to reply anyway because screw you guys: \n\n[image] \n\nAnd…","avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","slug":"why-is-there-a-topic-reply-limit-for-new-users","topic_id":11513,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":7,"reply_to_post_number":6,"username":"codinghorror","name":"Jeff Atwood","user_id":32,"acting_username":"codinghorror","acting_name":"Jeff Atwood","acting_user_id":32,"title":"Why is there a topic reply limit for new users?","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":6,"created_at":"2013-12-19T23:00:53Z","excerpt":"Thanks <a class='mention' href='/users/eviltrout'>@eviltrout</a> so I would have to use the url \n\ndiscouse.example.com/signup? \n\nThat works just fine. \n\nSo here is what im trying to accomplish: \n\n\nI'd like to make a link that is discouse.example.com/signup \nlaunch the signup modal over the normal home page. \nI'd like it be a plugin so I don't ha…","avatar_template":"//www.gravatar.com/avatar/1eb9fb4ff9cc03087229f202103f1d31.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/1eb9fb4ff9cc03087229f202103f1d31.png?s={size}&r=pg&d=identicon","slug":"plugin-to-make-signup-modal-pop-up-at-a-route","topic_id":11486,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":4,"reply_to_post_number":3,"username":"williscool","name":"will","user_id":7495,"acting_username":"williscool","acting_name":"will","acting_user_id":7495,"title":"Plugin to make signup modal pop up at a route","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":6,"created_at":"2013-12-19T22:23:41Z","excerpt":"Okay, set up a VM as you said, and everythings building fine now. Ruby is up and running, however, the page takes an average of 40 seconds to load. Console output shows nothing unsual (for me). \n\nPS D:\\Dev\\Workspaces\\discourse> vagrant ssh -c "bundle exec rails s"\nln: failed to create symbolic link …","avatar_template":"//www.gravatar.com/avatar/48b465ea4a935f74ad3711211b3f1ed8.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/48b465ea4a935f74ad3711211b3f1ed8.png?s={size}&r=pg&d=identicon","slug":"discourse-as-your-first-rails-app","topic_id":5751,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":67,"reply_to_post_number":66,"username":"npruehs","name":"npruehs","user_id":7959,"acting_username":"npruehs","acting_name":"npruehs","acting_user_id":7959,"title":"Discourse as Your First Rails App","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":7,"created_at":"2013-12-16T21:55:21Z","excerpt":"<a class='mention' href='/users/eviltrout'>@eviltrout</a> maybe we should pull the poll plugin, it's so old it is just a minefield at this point?","avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","slug":"how-when-to-bind-to-events-on-containerviews","topic_id":11466,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":4,"reply_to_post_number":2,"username":"codinghorror","name":"Jeff Atwood","user_id":32,"acting_username":"codinghorror","acting_name":"Jeff Atwood","acting_user_id":32,"title":"How/when to bind to events on ContainerViews?","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":7,"created_at":"2013-12-15T20:29:02Z","excerpt":"Is this fixed now <a class='mention' href='/users/eviltrout'>@eviltrout</a>?","avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","slug":"parsing-issues-when-using-github-style-markdown-for-code-blocks","topic_id":9361,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":3,"reply_to_post_number":null,"username":"codinghorror","name":"Jeff Atwood","user_id":32,"acting_username":"codinghorror","acting_name":"Jeff Atwood","acting_user_id":32,"title":"Parsing issues when using GitHub style markdown for code blocks","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":7,"created_at":"2013-12-15T07:41:56Z","excerpt":"There were some recent changes by <a class='mention' href='/users/eviltrout'>@eviltrout</a> that will make this work less well than it used to, because earlier posts are now unloaded (partially) to free memory in the browser as you scroll down. They won't be findable on the page -- they really aren't on the page any more. \n\nOtherwise if you ente…","avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","slug":"ctrl-f-search-is-interrupted-by-quotation-popup","topic_id":7114,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":11,"reply_to_post_number":10,"username":"codinghorror","name":"Jeff Atwood","user_id":32,"acting_username":"codinghorror","acting_name":"Jeff Atwood","acting_user_id":32,"title":"Ctrl+F search is interrupted by quotation popup","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":7,"created_at":"2013-12-15T07:34:52Z","excerpt":"<a class='mention' href='/users/eviltrout'>@eviltrout</a> we should fix this -- if a topic is muted I don't think close messages (or any sort of staff message) should show them as new messages.","avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","slug":"mark-all-read-button-on-all-new-and-unread-topics","topic_id":11434,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":10,"reply_to_post_number":6,"username":"codinghorror","name":"Jeff Atwood","user_id":32,"acting_username":"codinghorror","acting_name":"Jeff Atwood","acting_user_id":32,"title":"\"Mark all read\" button on all New and Unread topics","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":6,"created_at":"2013-12-13T20:06:43Z","excerpt":"you and should are both stop words [smile] maybe its time to experiment with a trigram based search","avatar_template":"//www.gravatar.com/avatar/3dcae8378d46c244172a115c28ca49ce.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/3dcae8378d46c244172a115c28ca49ce.png?s={size}&r=pg&d=identicon","slug":"search-not-working-for-staff-users","topic_id":11371,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":12,"reply_to_post_number":11,"username":"sam","name":"Sam Saffron","user_id":1,"acting_username":"sam","acting_name":"Sam Saffron","acting_user_id":1,"title":"Search not working for Staff users","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":6,"created_at":"2013-12-13T19:47:24Z","excerpt":"ha ? \n\n[image]","avatar_template":"//www.gravatar.com/avatar/3dcae8378d46c244172a115c28ca49ce.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/3dcae8378d46c244172a115c28ca49ce.png?s={size}&r=pg&d=identicon","slug":"search-not-working-for-staff-users","topic_id":11371,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":10,"reply_to_post_number":9,"username":"sam","name":"Sam Saffron","user_id":1,"acting_username":"sam","acting_name":"Sam Saffron","acting_user_id":1,"title":"Search not working for Staff users","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":6,"created_at":"2013-12-13T08:02:49Z","excerpt":"Oh my ... probably a bug in Rails, worked around it for now \n\n<a href='https://github.com/discourse/discourse/commit/1649f56529eafdf073c74c85f74238972202f2e1' target='_blank'>https://github.com/discourse/discourse/commit/1649f56529eafdf073c74c85f74238972202f2e1</a>","avatar_template":"//www.gravatar.com/avatar/3dcae8378d46c244172a115c28ca49ce.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/3dcae8378d46c244172a115c28ca49ce.png?s={size}&r=pg&d=identicon","slug":"search-not-working-for-staff-users","topic_id":11371,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":5,"reply_to_post_number":3,"username":"sam","name":"Sam Saffron","user_id":1,"acting_username":"sam","acting_name":"Sam Saffron","acting_user_id":1,"title":"Search not working for Staff users","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null}]}; Discourse.URL_FIXTURES["/user_actions.json?offset=0&username=eviltrout&filter=1"] = {"user_actions":[{"action_type":1,"created_at":"2014-01-10T20:07:46Z","excerpt":"We can't repro that one, also seems a bit obscure. But thank you very much for all the reports, whenever I see a bug entry from YOU I always know it is going to be a good one based on experience here and elsewhere. [trophy]","avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","slug":"security-error-on-console-noticed-on-meta","topic_id":11825,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":12,"reply_to_post_number":11,"username":"codinghorror","name":"Jeff Atwood","user_id":32,"acting_username":"eviltrout","acting_name":"Robin Ward","acting_user_id":19,"title":"Security Error on console (noticed on meta)","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":1,"created_at":"2014-01-07T15:08:42Z","excerpt":"Excellent, thank you, for the record I did all the work and <a class='mention' href='/users/eviltrout'>@eviltrout</a> <a class='mention' href='/users/sam'>@sam</a> <a class='mention' href='/users/neil'>@neil</a> <a class='mention' href='/users/zogstrip'>@zogstrip</a> did virtually nothing. I only list them here to be polite. \n\nOne way you can help the project: spread the word about Discourse, so more people may discover us and know there is a non-terrible free forum optio…","avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","slug":"awesomenesssss-it-is","topic_id":11462,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":4,"reply_to_post_number":null,"username":"codinghorror","name":"Jeff Atwood","user_id":32,"acting_username":"eviltrout","acting_name":"Robin Ward","acting_user_id":19,"title":"Awesomenesssss it is","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":1,"created_at":"2014-01-06T15:32:42Z","excerpt":"Yes! Since plugins are now able to override handlebars templates (thanks again, <a class='mention' href='/users/zogstrip'>@zogstrip</a> ) we have finally been able to create a clean Google AdSense plugin for Discourse. \n\nIt's available at <a href='https://github.com/discoursehosting/discourse-adsense' rel='nofollow'>https://github.com/discoursehosting/discourse-adsense</a> \n\nTo install: \n\n\nMake sure you're on latest! The <a href='https://github.com/discourse/discourse/commit/7fd88a52c9cc9d0e6e7bab3a3f8d3e8456b75d75' rel='nofollow'>chan…</a>","avatar_template":"//localhost:3000/uploads/default/avatars/886/ea8/e533d87fd9/{size}.png","acting_avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","slug":"google-adsense-plugin-is-now-available","topic_id":11763,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":1,"reply_to_post_number":null,"username":"michaeld","name":"Michael","user_id":6548,"acting_username":"eviltrout","acting_name":"Robin Ward","acting_user_id":19,"title":"Google AdSense plugin is now available","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":1,"created_at":"2014-01-03T15:35:30Z","excerpt":"Oh, cool! I wasn't sure what the path was to add comments for just random pages. I didn't think it'd actually crawl forward... that's really useful. \n\nForever ago I said that I'd adapt the little script I wrote to work with ghost, but with this new feature it's actually very easy, and not needed! Th…","avatar_template":"//localhost:3000/uploads/default/avatars/527/614/d16e1504d9/{size}.jpg","acting_avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","slug":"discourse-plugin-for-static-site-generators-like-jekyll-or-octopress","topic_id":7965,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":90,"reply_to_post_number":88,"username":"trident","name":"Ben T","user_id":5707,"acting_username":"eviltrout","acting_name":"Robin Ward","acting_user_id":19,"title":"Discourse plugin for static site generators like Jekyll or Octopress","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":1,"created_at":"2013-12-19T16:50:17Z","excerpt":"Here's the up-to-date list of all the hooks available in Discourse: \n\nClient-side (javascript)\n\naddCustomIcon\n\nEvent triggered by the TopicStatusComponent when rendering the icons representing the status of a topic. \n\nHow to use it? \n\n Discourse.TopicStatusComponent.reopen({\n onAddCustomIcon: funct…","avatar_template":"//www.gravatar.com/avatar/b7797beb47cfb7aa0fe60d09604aaa09.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","slug":"wip-list-of-all-the-hooks-in-discourse","topic_id":11505,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":1,"reply_to_post_number":null,"username":"zogstrip","name":"Régis Hanol","user_id":1995,"acting_username":"eviltrout","acting_name":"Robin Ward","acting_user_id":19,"title":"[WIP] List of all the hooks in Discourse","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":1,"created_at":"2013-12-06T19:50:56Z","excerpt":"Guessing it's largely because a lot of box-shadows were removed — rendering a dozen of those on a page can certainly hog some resources.","avatar_template":"//www.gravatar.com/avatar/9744a2573a43bb6d76deef82b7424023.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","slug":"miniprofiler-times-whats-appropriate-whats-fast-whats-cause-for-concern","topic_id":8150,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":8,"reply_to_post_number":7,"username":"awesomerobot","name":"Kris","user_id":2770,"acting_username":"eviltrout","acting_name":"Robin Ward","acting_user_id":19,"title":"Miniprofiler times - what's appropriate? What's fast? What's cause for concern?","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":1,"created_at":"2013-12-06T16:21:55Z","excerpt":"Confirmed, also here: \n\n[image] \n\nClient side is faster than ever, I am getting first paint at 489ms, it used to be 1122ms ... massive improvement, and I am noticing it. \n\nI attribute this to work <a class='mention' href='/users/eviltrout'>@eviltrout</a> has done and latest ember upgrades.","avatar_template":"//www.gravatar.com/avatar/3dcae8378d46c244172a115c28ca49ce.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","slug":"miniprofiler-times-whats-appropriate-whats-fast-whats-cause-for-concern","topic_id":8150,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":5,"reply_to_post_number":4,"username":"sam","name":"Sam Saffron","user_id":1,"acting_username":"eviltrout","acting_name":"Robin Ward","acting_user_id":19,"title":"Miniprofiler times - what's appropriate? What's fast? What's cause for concern?","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":1,"created_at":"2013-12-02T15:27:35Z","excerpt":"I would like to make a call here so we can merge in: \n\n<a href='https://github.com/discourse/discourse/pull/1658' target='_blank'>https://github.com/discourse/discourse/pull/1658</a> \n\nProcesses / services to go in app/services \n\nClass to be named UserActivator \n\n<a class='mention' href='/users/salbertson'>@salbertson</a> any chance you can update your PR so we can merge in?","avatar_template":"//www.gravatar.com/avatar/3dcae8378d46c244172a115c28ca49ce.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","slug":"process-objects","topic_id":11056,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":5,"reply_to_post_number":null,"username":"sam","name":"Sam Saffron","user_id":1,"acting_username":"eviltrout","acting_name":"Robin Ward","acting_user_id":19,"title":"\"Process\" objects","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":1,"created_at":"2013-11-21T22:04:10Z","excerpt":"This time we're going to add a button after every post that will allow users to hide/show the post. \n\nBut first, we need to understand how these buttons are generated. \n\nThey are defined by the post_menu site setting: [image] \n\nThis setting determine which items will appear on the post menu and thei…","avatar_template":"//www.gravatar.com/avatar/b7797beb47cfb7aa0fe60d09604aaa09.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","slug":"plugin-tutorial-3-how-to-add-a-button-after-every-posts","topic_id":11050,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":1,"reply_to_post_number":null,"username":"zogstrip","name":"Régis Hanol","user_id":1995,"acting_username":"eviltrout","acting_name":"Robin Ward","acting_user_id":19,"title":"Plugin tutorial #3 - How to add a button after every posts?","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":1,"created_at":"2013-11-19T17:49:36Z","excerpt":"I've recently pushed some code that will automatically load locales files provided they are in the /config/locales directory of your plugin and use our naming convention (eg. client.XX.yml and server.XX.yml) \n\n<a href='https://github.com/discourse/discourse/commit/291acca4fa106ef61213e0a0be0baf87c1093030' target='_blank'>https://github.com/discourse/discourse/commit/291acca4fa106ef61213e0a0be0baf87c1093030</a>","avatar_template":"//www.gravatar.com/avatar/b7797beb47cfb7aa0fe60d09604aaa09.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","slug":"plugin-i18n-setup","topic_id":9616,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":6,"reply_to_post_number":null,"username":"zogstrip","name":"Régis Hanol","user_id":1995,"acting_username":"eviltrout","acting_name":"Robin Ward","acting_user_id":19,"title":"Plugin i18n setup","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":1,"created_at":"2013-11-13T19:44:45Z","excerpt":"So, you want to manipulate the text in the composer but have no idea how? Let met guide you through the creation of a basic plugin that will turn the text into <a href='http://en.wikipedia.org/wiki/International_Talk_Like_a_Pirate_Day' rel='nofollow'>Pirate Speak</a>. \n\nFirst of all, you need to create a plugin.rb file that will be your entry point. \n\n # name: pirate-speak\n# about: plugin tha…","avatar_template":"//www.gravatar.com/avatar/b7797beb47cfb7aa0fe60d09604aaa09.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","slug":"plugin-tutorial-1-how-to-manipulate-the-text-in-the-composer","topic_id":10925,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":1,"reply_to_post_number":null,"username":"zogstrip","name":"Régis Hanol","user_id":1995,"acting_username":"eviltrout","acting_name":"Robin Ward","acting_user_id":19,"title":"Plugin Tutorial #1 - How to manipulate the text in the composer?","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":1,"created_at":"2013-11-12T17:23:44Z","excerpt":"Just fixed this issue. Hopefully, breaking your CSS won't break your forum anymore [smile] \n\n<a href='https://github.com/discourse/discourse/commit/e9f9d22482579761bbcce4a6c96d966405c93dd6' target='_blank'>https://github.com/discourse/discourse/commit/e9f9d22482579761bbcce4a6c96d966405c93dd6</a> \n\nThis commit changes the way the CSS error is displayed. Previously, it would hide the whole forum to display the error…","avatar_template":"//www.gravatar.com/avatar/b7797beb47cfb7aa0fe60d09604aaa09.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","slug":"customizing-my-css-broke-my-forum-with-no-easy-way-to-fix","topic_id":7203,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":20,"reply_to_post_number":null,"username":"zogstrip","name":"Régis Hanol","user_id":1995,"acting_username":"eviltrout","acting_name":"Robin Ward","acting_user_id":19,"title":"Customizing my CSS broke my forum with no easy way to fix","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":1,"created_at":"2013-11-12T17:01:09Z","excerpt":"my mistake, i should put: \n\nif (url.indexOf('u) != -1) return url;\n\nnow everyting working fine, and steps for subdirectory install are: \n\nin production.rb i added: \n\nconfig.relative_url_root = "/forum"\n config.action_controller.asset_host = "forum.domain.com"\n\nin jsapp/routes/discourse_location.js…","avatar_template":"//www.gravatar.com/avatar/383c468088614c59ea15115bc57f0489.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","slug":"discourse-on-subdirectory-doubling-relative-url-parameter","topic_id":10885,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":5,"reply_to_post_number":null,"username":"demil","name":"Dejan Milosevic","user_id":7498,"acting_username":"eviltrout","acting_name":"Robin Ward","acting_user_id":19,"title":"Discourse on subdirectory - doubling relative_url parameter","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":1,"created_at":"2013-11-04T19:50:03Z","excerpt":"As an exception, we have updated the software on the instance to master (instead of latest-release) so <a class='mention' href='/users/amitfrid'>@amitfrid</a> gets the fix immediately, given the severity of the bug in this particular case. \n\nI can now confirm that the problem is solved !","avatar_template":"//localhost:3000/uploads/default/avatars/886/ea8/e533d87fd9/{size}.png","acting_avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","slug":"new-category-system-bug-with-chinese-category-name","topic_id":10728,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":10,"reply_to_post_number":9,"username":"michaeld","name":"Michael","user_id":6548,"acting_username":"eviltrout","acting_name":"Robin Ward","acting_user_id":19,"title":"New category system bug with Chinese category name","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":1,"created_at":"2013-10-21T16:18:56Z","excerpt":"It's disorienting in this topic because we keep posting screenshots of the topic inside the topic. \n\n[image]","avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","slug":"flatter-styling-now-deployed","topic_id":10515,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":26,"reply_to_post_number":25,"username":"codinghorror","name":"Jeff Atwood","user_id":32,"acting_username":"eviltrout","acting_name":"Robin Ward","acting_user_id":19,"title":"Flatter styling now deployed","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":1,"created_at":"2013-10-17T14:08:05Z","excerpt":"As we have discussed in <a href='https://github.com/discourse/discourse/pull/1489' rel='nofollow'>this</a> and <a href='https://github.com/discourse/discourse/pull/1501' rel='nofollow'>this</a> pull request, Discourse.debounce and Discourse.debouncePromise currently behave inconsistently and a little clean up of this code would be welcome. I have done some research on this topic (sorry for a delay with this) and here are the conclusions. \n\nPossible deb…","avatar_template":"//www.gravatar.com/avatar/127db1a98fec83952bac174cdd94803b.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","slug":"debounce-and-debouncepromise-clean-up","topic_id":10412,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":1,"reply_to_post_number":null,"username":"velesin","name":"Wojciech Zawistowski","user_id":6808,"acting_username":"eviltrout","acting_name":"Robin Ward","acting_user_id":19,"title":"Debounce and debouncePromise clean up","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":1,"created_at":"2013-10-17T05:16:56Z","excerpt":"FYI, there is <a href='http://meta.discourse.org/t/new-vagrant-box-discourse-0-9-7/10396'>a new vagrant image</a>. Since you're just getting started, I recommend you use it.","avatar_template":"//www.gravatar.com/avatar/42776c4982dff1fa45ee8248532f8ad0.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","slug":"error-when-setting-up-discourse-0-8-4-box","topic_id":10166,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":11,"reply_to_post_number":null,"username":"neil","name":"Neil","user_id":2,"acting_username":"eviltrout","acting_name":"Robin Ward","acting_user_id":19,"title":"Error when setting up discourse-0.8.4.box","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":1,"created_at":"2013-10-16T19:53:53Z","excerpt":"There's a new vagrant box available with these changes: \n\n\nauth_token column in the users table has been cleared. It was identical for all users, which caused weird behaviour when logging in.\nthe <a href='http://mailcatcher.me/' rel='nofollow'>mailcatcher</a> gem is installed by default, with an alias mc to launch it. Don't bother trying to setup sen…","avatar_template":"//www.gravatar.com/avatar/42776c4982dff1fa45ee8248532f8ad0.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","slug":"new-vagrant-box-discourse-0-9-7","topic_id":10396,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":1,"reply_to_post_number":null,"username":"neil","name":"Neil","user_id":2,"acting_username":"eviltrout","acting_name":"Robin Ward","acting_user_id":19,"title":"New Vagrant box: discourse-0.9.7","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":1,"created_at":"2013-10-16T14:31:07Z","excerpt":"I guess we hate fun then ... THANK YOU <a class='mention' href='/users/eviltrout'>@eviltrout</a> [smile] \n\n[image]","avatar_template":"//www.gravatar.com/avatar/3dcae8378d46c244172a115c28ca49ce.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","slug":"js-ruby-sanitizer-difference","topic_id":9728,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":4,"reply_to_post_number":3,"username":"sam","name":"Sam Saffron","user_id":1,"acting_username":"eviltrout","acting_name":"Robin Ward","acting_user_id":19,"title":"JS & Ruby sanitizer difference","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":1,"created_at":"2013-10-15T14:04:19Z","excerpt":"Here's a jQuery snippet that I use to display latest discourse topics on another site. \n\n<a href='https://gist.github.com/surrealroad/6990268' target='_blank'>https://gist.github.com/surrealroad/6990268</a>","avatar_template":"//www.gravatar.com/avatar/3709f34da1ff5433b41bc56df94dd453.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","slug":"jquery-plugin-to-display-latest-posts","topic_id":10375,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":1,"reply_to_post_number":null,"username":"NinjaFoodstuff","name":"Jack James","user_id":2600,"acting_username":"eviltrout","acting_name":"Robin Ward","acting_user_id":19,"title":"Jquery plugin to display latest posts","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":1,"created_at":"2013-10-11T15:04:29Z","excerpt":"Discourse is a distributed team on several different continents and time zones. In fact, some of us have never even met in real life. Until the Discourse Team Building Exercise 2013, that is. (Pictured from left: Robin, Régis, Neil, Sam) The whole Discourse team flew in to San Francisco for a week t…","avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","slug":"discourse-team-building-exercise-2013","topic_id":10309,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":1,"reply_to_post_number":null,"username":"codinghorror","name":"Jeff Atwood","user_id":32,"acting_username":"eviltrout","acting_name":"Robin Ward","acting_user_id":19,"title":"Discourse Team Building Exercise 2013","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":1,"created_at":"2013-10-07T16:43:51Z","excerpt":"How dare you! Ok fine, I'll make a new image this week.","avatar_template":"//www.gravatar.com/avatar/42776c4982dff1fa45ee8248532f8ad0.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","slug":"error-when-setting-up-discourse-0-8-4-box","topic_id":10166,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":7,"reply_to_post_number":null,"username":"neil","name":"Neil","user_id":2,"acting_username":"eviltrout","acting_name":"Robin Ward","acting_user_id":19,"title":"Error when setting up discourse-0.8.4.box","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":1,"created_at":"2013-10-04T14:30:43Z","excerpt":"Absolutely you can, it's your house. If someone came into your house and starting yelling at you and constantly arguing with you, wouldn't you ask them to please leave? \n\nUnless you're married to that person of course.","avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","slug":"how-to-deal-with-unwelcome-people-in-your-community","topic_id":10176,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":11,"reply_to_post_number":5,"username":"codinghorror","name":"Jeff Atwood","user_id":32,"acting_username":"eviltrout","acting_name":"Robin Ward","acting_user_id":19,"title":"How to deal with unwelcome people in your community?","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":1,"created_at":"2013-10-03T16:12:40Z","excerpt":"Agreed. The use-case described here isn't a good reason to implement mute (from someone who has implemented it several times, and always regretted it and rolled it back...) What you really want is community feedback for behavior modification, like this: \n\n \n\nNo community has to tolerate unproduc…","avatar_template":"//www.gravatar.com/avatar/6c38e00d92cd9bd3ada3392b15015553.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","slug":"how-to-deal-with-unwelcome-people-in-your-community","topic_id":10176,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":9,"reply_to_post_number":8,"username":"frandallfarmer","name":"F. Randall Farmer","user_id":38,"acting_username":"eviltrout","acting_name":"Robin Ward","acting_user_id":19,"title":"How to deal with unwelcome people in your community?","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":1,"created_at":"2013-10-02T21:39:35Z","excerpt":"Today we released Cloud 66 EasyDeploy for Discourse: <a href='https://github.com/cloud66-samples/discourse' rel='nofollow'>https://github.com/cloud66-samples/discourse</a> \n\nLinke here: <a href='http://blog.cloud66.com/post/62900887610/open-source-meet-easydeploy' rel='nofollow'>http://blog.cloud66.com/post/62900887610/open-source-meet-easydeploy</a> \n\nThis is a fork of the main repo with no changes to the code and only a .cloud66 folder added. Using this, you can dep…","avatar_template":"//www.gravatar.com/avatar/07415248b6492231d9d41aba711cb93d.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","slug":"cloud-66-easydeploy-for-discourse","topic_id":10164,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":1,"reply_to_post_number":null,"username":"khash","name":"Khash Sajadi","user_id":5166,"acting_username":"eviltrout","acting_name":"Robin Ward","acting_user_id":19,"title":"Cloud 66 EasyDeploy for Discourse","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":1,"created_at":"2013-10-02T21:39:25Z","excerpt":"self it is, <a class='mention' href='/users/velesin'>@velesin</a> feel free to work through this, slowly, paving the testing through the way. Thanks heaps, appreciate all the js work you have been doing.","avatar_template":"//www.gravatar.com/avatar/3dcae8378d46c244172a115c28ca49ce.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","slug":"inconsistent-javascript-context-binding","topic_id":9880,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":6,"reply_to_post_number":2,"username":"sam","name":"Sam Saffron","user_id":1,"acting_username":"eviltrout","acting_name":"Robin Ward","acting_user_id":19,"title":"Inconsistent JavaScript context binding","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":1,"created_at":"2013-10-02T14:10:42Z","excerpt":"Have you even looked at other forum software? At all? I find it frankly laughable to say that Discourse is "tech oriented" relative to other forum software. Here's a little taste: \n\n <a href='/uploads/meta_discourse/546/fb18659dec79d92e.png' class='lightbox' title='fb18659dec79d92e.png'>[image]\nfb18659dec79d92e.png677x748\n</a>\n\nWe can argue all we want about the semantics of "create topic" versus "start…","avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","slug":"ui-issue-create-topic-should-be-on-left-side-of-screen","topic_id":10152,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":6,"reply_to_post_number":4,"username":"codinghorror","name":"Jeff Atwood","user_id":32,"acting_username":"eviltrout","acting_name":"Robin Ward","acting_user_id":19,"title":"UI Issue - \"Create Topic\" should be on Left side of screen","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":1,"created_at":"2013-10-01T21:13:38Z","excerpt":"Just to let you know guys that we've deployed the new <a href='https://github.com/discourse/discourse-spoiler-alert' rel='nofollow'>spoiler alert plugin</a> here on meta and it also works with images [wink] \n\n[image]","avatar_template":"//www.gravatar.com/avatar/b7797beb47cfb7aa0fe60d09604aaa09.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","slug":"how-do-you-spoiler-an-image-or-onebox","topic_id":55,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":15,"reply_to_post_number":null,"username":"zogstrip","name":"Régis Hanol","user_id":1995,"acting_username":"eviltrout","acting_name":"Robin Ward","acting_user_id":19,"title":"How do you spoiler an image or onebox?","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":1,"created_at":"2013-09-27T00:52:51Z","excerpt":"Performance video demo we recorded today:","avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","slug":"why-is-discourse-so-slow-on-android","topic_id":8823,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":38,"reply_to_post_number":null,"username":"codinghorror","name":"Jeff Atwood","user_id":32,"acting_username":"eviltrout","acting_name":"Robin Ward","acting_user_id":19,"title":"Why is Discourse so slow on Android?","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":1,"created_at":"2013-09-24T21:44:58Z","excerpt":"The Discourse team are all going to be around San Francisco for a week starting Wednesday. We are all attending the GoGaRuCo conference. \n\nWe thought it would be great if we could have a Discourse meetup on Tuesday around 5pm, trouble is we need a venue. \n\nWas hoping perhaps our friends at GitHub o…","avatar_template":"//www.gravatar.com/avatar/3dcae8378d46c244172a115c28ca49ce.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","slug":"discourse-meetup-in-san-francisco-tuesday-the-24th-of-september","topic_id":9839,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":1,"reply_to_post_number":null,"username":"sam","name":"Sam Saffron","user_id":1,"acting_username":"eviltrout","acting_name":"Robin Ward","acting_user_id":19,"title":"Discourse meetup in San Francisco, Tuesday the 24th of September","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":1,"created_at":"2013-09-17T23:48:21Z","excerpt":"I will see you there!","avatar_template":"//www.gravatar.com/avatar/6c38e00d92cd9bd3ada3392b15015553.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","slug":"discourse-meetup-in-san-francisco-tuesday-the-24th-of-september","topic_id":9839,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":8,"reply_to_post_number":null,"username":"frandallfarmer","name":"F. Randall Farmer","user_id":38,"acting_username":"eviltrout","acting_name":"Robin Ward","acting_user_id":19,"title":"Discourse meetup in San Francisco, Tuesday the 24th of September","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":1,"created_at":"2013-09-17T23:48:20Z","excerpt":"Daaaaang. I'm flying out that morning. Looking forward to meeting you folks at GoGaRuCo though.","avatar_template":"//www.gravatar.com/avatar/4fafaca2401263fd03b62ff37a157a35.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","slug":"discourse-meetup-in-san-francisco-tuesday-the-24th-of-september","topic_id":9839,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":7,"reply_to_post_number":null,"username":"chrishunt","name":"Chris Hunt","user_id":247,"acting_username":"eviltrout","acting_name":"Robin Ward","acting_user_id":19,"title":"Discourse meetup in San Francisco, Tuesday the 24th of September","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":1,"created_at":"2013-09-16T18:35:01Z","excerpt":"Oh my [smile] \n\nYou are going to need to "mod" yourself. Try \n\n RAILS_ENV=production bundle exec rails c\n> u = User.first \n> u.admin = true \n> u.save","avatar_template":"//www.gravatar.com/avatar/3dcae8378d46c244172a115c28ca49ce.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","slug":"install-tutorial-for-the-ruby-dumb","topic_id":2027,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":15,"reply_to_post_number":14,"username":"sam","name":"Sam Saffron","user_id":1,"acting_username":"eviltrout","acting_name":"Robin Ward","acting_user_id":19,"title":"Install tutorial for the ruby-dumb?","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":1,"created_at":"2013-09-14T04:10:16Z","excerpt":"Hey, onebox gem team lead here. The good news is that <a href='http://ruby-doc.org/stdlib-1.9.3/libdoc/open-uri/rdoc/OpenURI/OpenRead.html' rel='nofollow'>http://ruby-doc.org/stdlib-1.9.3/libdoc/open-uri/rdoc/OpenURI/OpenRead.html</a> does in fact have a timeout option. We'll be implementing this functionality for next release. \n\nSee progress here: <a href='https://github.com/dysania/onebox/issues/123' rel='nofollow'>https://github.com/dysania/onebox/issues/123</a>","avatar_template":"//www.gravatar.com/avatar/15d21696a56b183503cf2c82114be9d6.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","slug":"sometimes-onebox-hangs","topic_id":9010,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":9,"reply_to_post_number":null,"username":"krainboltgreene","name":"Kurtis Rainbolt-Greene","user_id":6330,"acting_username":"eviltrout","acting_name":"Robin Ward","acting_user_id":19,"title":"Sometimes onebox hangs","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":1,"created_at":"2013-08-29T17:16:19Z","excerpt":"Becomes the above when quote replied. \n\nWhich brings up a second bug ... vvvv should really look like \n\n \n\n \n\nAnd a third bug \n\n [quote="sam, post:1, topic:9441, full:true"]\nThis is `<not>` a bug.\n[/quote]","avatar_template":"//www.gravatar.com/avatar/3dcae8378d46c244172a115c28ca49ce.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","slug":"quoting-should-keep-tags-escaped","topic_id":9441,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":2,"reply_to_post_number":null,"username":"sam","name":"Sam Saffron","user_id":1,"acting_username":"eviltrout","acting_name":"Robin Ward","acting_user_id":19,"title":"Quoting should keep tags escaped","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":1,"created_at":"2013-08-24T19:49:28Z","excerpt":"That is the goal but it may take some time to get there!","avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","slug":"will-installation-of-discourse-ever-gonna-be-simple-as-it-is-for-wordpress","topic_id":9312,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":5,"reply_to_post_number":null,"username":"codinghorror","name":"Jeff Atwood","user_id":32,"acting_username":"eviltrout","acting_name":"Robin Ward","acting_user_id":19,"title":"Will installation of Discourse ever gonna be simple as it is for Wordpress?","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":1,"created_at":"2013-07-23T21:19:11Z","excerpt":"wow, that was incredibly easy. was expecting it to get a little hairy somewhere! \n\nreally, really spectacular feature team, great work. \n\nsaves me a number of "hey, this email that you sent didn't go where you think it did, you gotta log back in" emails!","avatar_template":"//localhost:3000/uploads/default/avatars/0cd/a15/fa37f06925/{size}.jpeg","acting_avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","slug":"new-reply-via-email-support","topic_id":7764,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":15,"reply_to_post_number":14,"username":"SBauch","name":"Sam Bauch","user_id":2876,"acting_username":"eviltrout","acting_name":"Robin Ward","acting_user_id":19,"title":"New: Reply via Email Support!","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":1,"created_at":"2013-07-18T21:56:21Z","excerpt":"I'll just drop this here: \n\n<a href='https://github.com/cfstras/discourse-konami' rel='nofollow'>https://github.com/cfstras/discourse-konami</a>It's built on <a href='http://snaptortoise.com/konami-js/' rel='nofollow'>Konami-JS</a>, which made this really easy :) \n\nTo Install, add this line to your Gemfile: \n\ngem 'discourse_konami', :git => 'https://github.com/cfstras/discourse-konami'\n\nexecute: \n\n$ bundle install\n$ rake assets:preco…","avatar_template":"//www.gravatar.com/avatar/18c103ae1020a5a9ceefe80ae83af5d5.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","slug":"plugin-the-konami-code","topic_id":8473,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":1,"reply_to_post_number":null,"username":"cfstras","name":"Claus Strasburger","user_id":1496,"acting_username":"eviltrout","acting_name":"Robin Ward","acting_user_id":19,"title":"Plugin: The Konami Code","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":1,"created_at":"2013-07-17T19:46:22Z","excerpt":"Hi everybody, \n\nI work at Heroku and am managing our little forums experiment. I plan on creating a new fork of Discourse shortly that will contain everything we needed to do to get it running on Heroku. Teaser: it wasn't much at all and I have hopes that someday there will be no diversion from mast…","avatar_template":"//www.gravatar.com/avatar/8eb7bf96dd877adca0cbd29bb2e47e38.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","slug":"anyone-got-this-running-on-heroku-yet","topic_id":625,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":124,"reply_to_post_number":null,"username":"rwdaigle","name":"rwdaigle","user_id":6128,"acting_username":"eviltrout","acting_name":"Robin Ward","acting_user_id":19,"title":"Anyone got this running on Heroku yet?","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":1,"created_at":"2013-07-16T17:49:47Z","excerpt":"I was thinking, if we just added a hyperlink directly underneath your username, it could coerce users to fill in about me sections. \n\n[image] \n\nThe rules are simple \n\n\nOnly shows up when you are looking at your avatar/username \nAnd clearly only shows up when its blank \nLink takes you to your edit pr…","avatar_template":"//www.gravatar.com/avatar/3dcae8378d46c244172a115c28ca49ce.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","slug":"stronger-hinting-to-fill-stuff-in-about-me-field","topic_id":8409,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":1,"reply_to_post_number":null,"username":"sam","name":"Sam Saffron","user_id":1,"acting_username":"eviltrout","acting_name":"Robin Ward","acting_user_id":19,"title":"Stronger hinting to fill stuff in about me field","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":1,"created_at":"2013-07-12T20:52:21Z","excerpt":"And a <a href='http://blog.discourse.org/2013/07/improved-image-handling/'>blog post</a>.","avatar_template":"//www.gravatar.com/avatar/69fda0df8b4878fb6a18deffa972d26a.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","slug":"thumbnails-and-original-images-in-posts","topic_id":8321,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":3,"reply_to_post_number":null,"username":"erlend_sh","name":"Erlend Sogge Heggen","user_id":5351,"acting_username":"eviltrout","acting_name":"Robin Ward","acting_user_id":19,"title":"Thumbnails and original images in posts","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":1,"created_at":"2013-06-25T16:01:27Z","excerpt":"Continuing the discussion from <a href='http://meta.discourse.org/t/internationalization-localization/280/90'>Internationalization / localization</a>, which has become a massive, unfocused topic: \n\nLet's talk about translation tools and the process for getting translations done. If we were going to adopt a third-party tool to get translations done, which should be used? From the I…","avatar_template":"//www.gravatar.com/avatar/42776c4982dff1fa45ee8248532f8ad0.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","slug":"translation-tools-transifex-localeapp","topic_id":7763,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":1,"reply_to_post_number":null,"username":"neil","name":"Neil","user_id":2,"acting_username":"eviltrout","acting_name":"Robin Ward","acting_user_id":19,"title":"Translation Tools: Transifex? Localeapp?","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":1,"created_at":"2013-06-25T15:45:31Z","excerpt":"I use 1Password to log in to Discourse sites. You may need to click the + sign to create a new record, but it Works For Me™. \n\n[image]","avatar_template":"//www.gravatar.com/avatar/42776c4982dff1fa45ee8248532f8ad0.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","slug":"add-method-attribute-to-logon-form","topic_id":7741,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":6,"reply_to_post_number":null,"username":"neil","name":"Neil","user_id":2,"acting_username":"eviltrout","acting_name":"Robin Ward","acting_user_id":19,"title":"Add method attribute to logon form?","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":1,"created_at":"2013-06-25T03:03:44Z","excerpt":"I made a bunch of progress today see: \n\n<a href='https://github.com/discourse/discourse/commit/0b94c3c4561e7a6aae11658b3a799407d72ad2af' target='_blank'>https://github.com/discourse/discourse/commit/0b94c3c4561e7a6aae11658b3a799407d72ad2af</a> \n\nIn particular, I made it so SiteSettings delegate storage to a non-persitant store in test. This means that nothing really breaks if you type SiteSetting.some_setting = 1…","avatar_template":"//www.gravatar.com/avatar/3dcae8378d46c244172a115c28ca49ce.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","slug":"site-settings-refactoring","topic_id":7687,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":2,"reply_to_post_number":null,"username":"sam","name":"Sam Saffron","user_id":1,"acting_username":"eviltrout","acting_name":"Robin Ward","acting_user_id":19,"title":"Site Settings Refactoring","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":1,"created_at":"2013-06-19T13:31:51Z","excerpt":"Andrew \n\nI am very humbled to have a response from you here, I do appreciate what you created with sugar, when <a class='mention' href='/users/eviltrout'>@eviltrout</a> picked it for Discourse it was not a decision he took on a whim. \n\nI am super excited you are taking a fresh look at performance, that is fantastic news. \n\nAfter quite a while…","avatar_template":"//www.gravatar.com/avatar/3dcae8378d46c244172a115c28ca49ce.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","slug":"getting-rid-of-sugar-js","topic_id":7146,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":8,"reply_to_post_number":7,"username":"sam","name":"Sam Saffron","user_id":1,"acting_username":"eviltrout","acting_name":"Robin Ward","acting_user_id":19,"title":"Getting rid of sugar.js","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":1,"created_at":"2013-06-19T13:31:47Z","excerpt":"Hello, creator of Sugar.js here. \n\nI realize you guys have come to a decision and sad to see you go but that's up to you... just want to add my 2 cents: \n\n1: \n\n You're totally right about performance and it's something that Sugar has/is/will be devoting more attention to. I have just done a major re…","avatar_template":"//www.gravatar.com/avatar/39255341a51574e9651b1094537e7683.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","slug":"getting-rid-of-sugar-js","topic_id":7146,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":7,"reply_to_post_number":null,"username":"l_andrew_l","name":"l_andrew_l","user_id":5610,"acting_username":"eviltrout","acting_name":"Robin Ward","acting_user_id":19,"title":"Getting rid of sugar.js","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":1,"created_at":"2013-06-12T14:09:25Z","excerpt":"Sugar.js is gone. \n\nThis makes me happy. I just don't buy that there is this magic need to amend every protoype in the system. It is fragile, risky and generally considered a bad practice, I don't buy that you need to wack 100 extra method on Array, String and so on. Also, Sugar unacceptably slow fo…","avatar_template":"//www.gravatar.com/avatar/3dcae8378d46c244172a115c28ca49ce.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","slug":"getting-rid-of-sugar-js","topic_id":7146,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":4,"reply_to_post_number":null,"username":"sam","name":"Sam Saffron","user_id":1,"acting_username":"eviltrout","acting_name":"Robin Ward","acting_user_id":19,"title":"Getting rid of sugar.js","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":1,"created_at":"2013-06-10T20:43:34Z","excerpt":"It was a bug. I fixed it today:","avatar_template":"//www.gravatar.com/avatar/42776c4982dff1fa45ee8248532f8ad0.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","slug":"unable-to-delete-categories","topic_id":7357,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":2,"reply_to_post_number":null,"username":"neil","name":"Neil","user_id":2,"acting_username":"eviltrout","acting_name":"Robin Ward","acting_user_id":19,"title":"Unable to delete categories!","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":1,"created_at":"2013-06-09T16:06:49Z","excerpt":"Your install is a mess, looks like a lot of the requests aren't even making it to Discourse: \n\nWhen I try to save preferences, I see this in the chrome console: \n\nPUT <a href='http://convinceyou.com/users/supermathie' rel='nofollow'>http://convinceyou.com/users/supermathie</a> 404 (Not Found) \n\nWhen I try to log out: \n\nDELETE <a href='http://convinceyou.com/session/supermathie' rel='nofollow'>http://convinceyou.com/session/supermathie</a> …","avatar_template":"//www.gravatar.com/avatar/44ae1b2d44d48aed3d432129a5703942.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","slug":"troubleshooting-failed-discourse-install","topic_id":7292,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":2,"reply_to_post_number":1,"username":"supermathie","name":"Michael Brown","user_id":3,"acting_username":"eviltrout","acting_name":"Robin Ward","acting_user_id":19,"title":"Troubleshooting failed Discourse install","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":1,"created_at":"2013-06-07T18:29:30Z","excerpt":"It's actually very tidy if we change the PostCreator constructor and think about pulling the whitelist logic into its own class. The request can stay the same and we get to re-use the filter in other controllers. Something like: \n\n # app/controllers/posts_controller.rb\nclass PostsControllers\n de…","avatar_template":"//www.gravatar.com/avatar/4fafaca2401263fd03b62ff37a157a35.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","slug":"ensuring-scalar-values-for-parameters-with-strong-parameters","topic_id":7235,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":12,"reply_to_post_number":10,"username":"chrishunt","name":"Chris Hunt","user_id":247,"acting_username":"eviltrout","acting_name":"Robin Ward","acting_user_id":19,"title":"Ensuring scalar values for parameters with strong_parameters","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":1,"created_at":"2013-06-06T21:28:41Z","excerpt":"So, you want to use S3 to handle image uploads? Here's the definitive guide: \n\nS3 registration\n\nHead over to <a href='http://aws.amazon.com/s3/' rel='nofollow'>http://aws.amazon.com/s3/</a> and click on [image]. \n\nDuring the create account process, make sure you provide payment information, otherwise you won't be able to use S3. There's no registration …","avatar_template":"//www.gravatar.com/avatar/b7797beb47cfb7aa0fe60d09604aaa09.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","slug":"how-to-set-up-image-uploads-to-s3","topic_id":7229,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":1,"reply_to_post_number":null,"username":"zogstrip","name":"Régis Hanol","user_id":1995,"acting_username":"eviltrout","acting_name":"Robin Ward","acting_user_id":19,"title":"How to set up image uploads to S3?","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":1,"created_at":"2013-06-06T15:07:28Z","excerpt":"The user model is one of our most biggest models, I totally support simplifying and decomposing. \n\nUsername suggestion stuff can be extracted out. We can introduce a UserCreator like we have a PostCreator and TopicCreator, update_last_seen! maybe can be moved to another spot. \n\nPR totally welcome. …","avatar_template":"//www.gravatar.com/avatar/3dcae8378d46c244172a115c28ca49ce.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","slug":"little-refactor-over-user-model-to-avoid-global-complexity","topic_id":7219,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":2,"reply_to_post_number":1,"username":"sam","name":"Sam Saffron","user_id":1,"acting_username":"eviltrout","acting_name":"Robin Ward","acting_user_id":19,"title":"Little refactor over User model to avoid global complexity","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":1,"created_at":"2013-06-06T05:47:36Z","excerpt":"Seems good! \n\nOf course, I should have checked other big projects, brains are very silly things. My thought was "oh, I don't know if this is true, I'll look at Discourse!" And rather than keep looking, I just stopped there.","avatar_template":"//www.gravatar.com/avatar/233c279c012ebac792aaa805f966cbc7.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","slug":"discourse-the-gpl-and-per-file-notice","topic_id":7208,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":4,"reply_to_post_number":3,"username":"steveklabnik","name":"steveklabnik","user_id":5413,"acting_username":"eviltrout","acting_name":"Robin Ward","acting_user_id":19,"title":"Discourse, the GPL, and per-file notice","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":1,"created_at":"2013-06-02T15:23:14Z","excerpt":"I got Ember.Control from wycats [smile]","avatar_template":"//www.gravatar.com/avatar/749001c9fe6927c4b069a45c2a3d68f7.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","slug":"discourse-ember-refactorings","topic_id":7019,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":4,"reply_to_post_number":3,"username":"ryanflorence","name":"ryanflorence","user_id":2702,"acting_username":"eviltrout","acting_name":"Robin Ward","acting_user_id":19,"title":"Discourse Ember Refactorings","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":1,"created_at":"2013-06-02T15:22:11Z","excerpt":"This is excellent <a class='mention' href='/users/eviltrout'>@eviltrout</a>! \n\nJust one remark, regarding this issue: \n\n \n\nWhen a view is enough, I really like what <a class='mention' href='/users/ryanflorence'>@ryanflorence</a> is doing in his screencasts with his Control view: \n\n Ember.Control = Ember.View.extend({\n init: function() {\n this._super();\n this.set('context', this);\n }\n})…","avatar_template":"//www.gravatar.com/avatar/b7797beb47cfb7aa0fe60d09604aaa09.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","slug":"discourse-ember-refactorings","topic_id":7019,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":3,"reply_to_post_number":2,"username":"zogstrip","name":"Régis Hanol","user_id":1995,"acting_username":"eviltrout","acting_name":"Robin Ward","acting_user_id":19,"title":"Discourse Ember Refactorings","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":1,"created_at":"2013-05-31T16:58:10Z","excerpt":"For the feature I was working on yesterday, <a class='mention' href='/users/codinghorror'>@codinghorror</a> wanted a rather complex sentence. \n\n There is 1 unread and 9 new topics remaining, or browse other topics in [category]\n\nThis seemingly simple sentence was a royal nightmare to localize with our existing localization system. Think through al…","avatar_template":"//www.gravatar.com/avatar/3dcae8378d46c244172a115c28ca49ce.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","slug":"message-format-support-for-localization","topic_id":7035,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":1,"reply_to_post_number":null,"username":"sam","name":"Sam Saffron","user_id":1,"acting_username":"eviltrout","acting_name":"Robin Ward","acting_user_id":19,"title":"Message Format support for localization","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":1,"created_at":"2013-05-31T16:58:07Z","excerpt":"I know this isn't really the point of your post, but I don't think that's correct. At least, it seems super-awkward to this American. Is it possible to rewrite the sentence entirely? Maybe something like this: \n\nYou have 1 unread topic and 9 new topics left, or browse other topics in [category]. \n…","avatar_template":"//www.gravatar.com/avatar/413ef976f0d2ca993005c9aee4769254.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","slug":"message-format-support-for-localization","topic_id":7035,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":2,"reply_to_post_number":1,"username":"BhaelOchon","name":"Bill Ayakatubby","user_id":471,"acting_username":"eviltrout","acting_name":"Robin Ward","acting_user_id":19,"title":"Message Format support for localization","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":1,"created_at":"2013-05-28T14:45:39Z","excerpt":"I believe you should use the uncategorized_name site setting for that.","avatar_template":"//www.gravatar.com/avatar/b7797beb47cfb7aa0fe60d09604aaa09.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","slug":"how-to-localize-the-uncategorized-category-name","topic_id":6947,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":2,"reply_to_post_number":1,"username":"zogstrip","name":"Régis Hanol","user_id":1995,"acting_username":"eviltrout","acting_name":"Robin Ward","acting_user_id":19,"title":"How to localize the “uncategorized” category name","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":1,"created_at":"2013-05-24T14:09:01Z","excerpt":"I'm digging into the Topic class along the same lines. I love cleaning, simplifying, and good OO design.","avatar_template":"//www.gravatar.com/avatar/985ff04dc441ad87b0cefcd31823575d.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","slug":"so-you-want-to-help-out-with-discourse","topic_id":3823,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":29,"reply_to_post_number":null,"username":"mattvanhorn","name":"Matt Van Horn","user_id":5103,"acting_username":"eviltrout","acting_name":"Robin Ward","acting_user_id":19,"title":"So, you want to help out with Discourse","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":1,"created_at":"2013-05-17T03:39:29Z","excerpt":"I got this question on twitter and wanted to touch on it here. \n\n\n \n \n <a href='https://twitter.com/nycplayer/status/335114964836679681' class='track-link' target='_blank'>\n [image] twitter.com\n </a>\n \n \n\n \n [image]\n <a href='https://twitter.com/nycplayer'>\n @nycplayer\n </a>\n \n\n @samsaffron Want to start helping w/ Discourse, is it OK w/ you to make PRs for minor stuff like changi…","avatar_template":"//www.gravatar.com/avatar/3dcae8378d46c244172a115c28ca49ce.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","slug":"where-does-discourse-stand-on-minor-refactoring-prs","topic_id":6677,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":1,"reply_to_post_number":null,"username":"sam","name":"Sam Saffron","user_id":1,"acting_username":"eviltrout","acting_name":"Robin Ward","acting_user_id":19,"title":"Where does Discourse stand on minor refactoring PRs","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null}]}; Discourse.URL_FIXTURES["/user_actions.json?offset=0&username=eviltrout&filter=2"] = {"user_actions":[{"action_type":2,"created_at":"2014-01-15T16:53:49Z","excerpt":"A good fix would be to have the ERB template do an if statement. We'd happily accept a PR that did this if you feel up to it: \n\n <% if SiteSetting.logo_url.present? %>\n display logo html\n<% else %>\n display title html\n<% end %>","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","slug":"users-activate-account-pulling-blank-logo-instead-of-defaulting-to-h2","topic_id":10911,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":3,"reply_to_post_number":2,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"codinghorror","acting_name":"Jeff Atwood","acting_user_id":32,"title":"/users/activate-account pulling blank logo instead of defaulting to h2","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":2,"created_at":"2014-01-15T00:54:32Z","excerpt":"You can retrieve a user's JSON by making a call to /users/username.json but that assumes you know the user's username. If that's impossible, I would be happy to accept a PR that would return the current user JSON from /session/current-user or something like that. \n\nAdditionally, if you're looking to…","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/035d12bad251759d8fbc9fb10574d1f6.png?s={size}&r=pg&d=identicon","slug":"get-current-user-information-via-json","topic_id":11959,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":2,"reply_to_post_number":null,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"watchmanmonitor","acting_name":"Watchman Monitoring","acting_user_id":8085,"title":"Get current user information via JSON","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":2,"created_at":"2014-01-14T21:59:51Z","excerpt":"You can retrieve a user's JSON by making a call to /users/username.json but that assumes you know the user's username. If that's impossible, I would be happy to accept a PR that would return the current user JSON from /session/current-user or something like that. \n\nAdditionally, if you're looking to…","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/9cfd2536afac32d209335b092094c12c.png?s={size}&r=pg&d=identicon","slug":"get-current-user-information-via-json","topic_id":11959,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":2,"reply_to_post_number":null,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"znation","acting_name":"znation","acting_user_id":8163,"title":"Get current user information via JSON","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":2,"created_at":"2014-01-14T21:46:50Z","excerpt":"Okay I've fixed the https [point_right] http links on the server side and in the Javascript click tracking as <a class='mention' href='/users/bhaelochon'>@BhaelOchon</a> pointed out. \n\nLet me know if you find anything else broken.","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","slug":"broken-links-possibly-related-to-https","topic_id":11831,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":18,"reply_to_post_number":16,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"codinghorror","acting_name":"Jeff Atwood","acting_user_id":32,"title":"Broken links, possibly related to HTTPS","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":2,"created_at":"2014-01-14T21:21:52Z","excerpt":"Okay I've fixed the https [point_right] http links on the server side and in the Javascript click tracking as <a class='mention' href='/users/bhaelochon'>@BhaelOchon</a> pointed out. \n\nLet me know if you find anything else broken.","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/b7797beb47cfb7aa0fe60d09604aaa09.png?s={size}&r=pg&d=identicon","slug":"broken-links-possibly-related-to-https","topic_id":11831,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":18,"reply_to_post_number":16,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"zogstrip","acting_name":"Régis Hanol","acting_user_id":1995,"title":"Broken links, possibly related to HTTPS","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":2,"created_at":"2014-01-14T20:42:51Z","excerpt":"You can retrieve a user's JSON by making a call to /users/username.json but that assumes you know the user's username. If that's impossible, I would be happy to accept a PR that would return the current user JSON from /session/current-user or something like that. \n\nAdditionally, if you're looking to…","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","slug":"get-current-user-information-via-json","topic_id":11959,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":2,"reply_to_post_number":null,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"codinghorror","acting_name":"Jeff Atwood","acting_user_id":32,"title":"Get current user information via JSON","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":2,"created_at":"2014-01-14T08:28:00Z","excerpt":"I've just added the ability to list reply counts on your blog index and archive pages as you <a href='http://eviltrout.com/archives/' rel='nofollow'>can see here</a>. \n\nIt works with a similar API to embedding comments: \n\n <script type="text/javascript">\n var discourseUrl = "http://fishtank.eviltrout.com/";\n\n (function() {\n var d = document.createEleme…","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/3dcae8378d46c244172a115c28ca49ce.png?s={size}&r=pg&d=identicon","slug":"discourse-plugin-for-static-site-generators-like-jekyll-or-octopress","topic_id":7965,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":98,"reply_to_post_number":null,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"sam","acting_name":"Sam Saffron","acting_user_id":1,"title":"Discourse plugin for static site generators like Jekyll or Octopress","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":2,"created_at":"2014-01-13T21:11:32Z","excerpt":"I had to fix an issue with Google analytics so I added a new API hook that can be used. \n\nIf you add the following it should work: \n\n Discourse.PageTracker.current().on('change', function() {\n _paq.push(['trackPageView']);\n});","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/3dcae8378d46c244172a115c28ca49ce.png?s={size}&r=pg&d=identicon","slug":"support-for-piwik-analytics-as-an-alternative-to-google-analytics","topic_id":7512,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":22,"reply_to_post_number":16,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"sam","acting_name":"Sam Saffron","acting_user_id":1,"title":"Support for Piwik Analytics as an alternative to Google Analytics","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":2,"created_at":"2014-01-13T20:50:34Z","excerpt":"I've just added the ability to list reply counts on your blog index and archive pages as you <a href='http://eviltrout.com/archives/' rel='nofollow'>can see here</a>. \n\nIt works with a similar API to embedding comments: \n\n <script type="text/javascript">\n var discourseUrl = "http://fishtank.eviltrout.com/";\n\n (function() {\n var d = document.createEleme…","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//localhost:3000/uploads/default/avatars/527/614/d16e1504d9/{size}.jpg","slug":"discourse-plugin-for-static-site-generators-like-jekyll-or-octopress","topic_id":7965,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":98,"reply_to_post_number":null,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"trident","acting_name":"Ben T","acting_user_id":5707,"title":"Discourse plugin for static site generators like Jekyll or Octopress","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":2,"created_at":"2014-01-13T20:44:56Z","excerpt":"I had to fix an issue with Google analytics so I added a new API hook that can be used. \n\nIf you add the following it should work: \n\n Discourse.PageTracker.current().on('change', function() {\n _paq.push(['trackPageView']);\n});","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/b7797beb47cfb7aa0fe60d09604aaa09.png?s={size}&r=pg&d=identicon","slug":"support-for-piwik-analytics-as-an-alternative-to-google-analytics","topic_id":7512,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":22,"reply_to_post_number":16,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"zogstrip","acting_name":"Régis Hanol","acting_user_id":1995,"title":"Support for Piwik Analytics as an alternative to Google Analytics","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":2,"created_at":"2014-01-13T19:52:04Z","excerpt":"<a class='mention' href='/users/sam'>@Sam</a> do you have any idea why only some people are getting this issue? I dont' mind the proposed fix but I'd prefer to know why it happens in the first place.","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/3dcae8378d46c244172a115c28ca49ce.png?s={size}&r=pg&d=identicon","slug":"error-after-update-to-0-9-8-1","topic_id":11903,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":10,"reply_to_post_number":null,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"sam","acting_name":"Sam Saffron","acting_user_id":1,"title":"Error after update to 0.9.8.1","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":2,"created_at":"2014-01-13T19:01:19Z","excerpt":"I've just added the ability to list reply counts on your blog index and archive pages as you <a href='http://eviltrout.com/archives/' rel='nofollow'>can see here</a>. \n\nIt works with a similar API to embedding comments: \n\n <script type="text/javascript">\n var discourseUrl = "http://fishtank.eviltrout.com/";\n\n (function() {\n var d = document.createEleme…","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","slug":"discourse-plugin-for-static-site-generators-like-jekyll-or-octopress","topic_id":7965,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":98,"reply_to_post_number":null,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"codinghorror","acting_name":"Jeff Atwood","acting_user_id":32,"title":"Discourse plugin for static site generators like Jekyll or Octopress","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":2,"created_at":"2014-01-13T18:50:14Z","excerpt":"I've just added the ability to list reply counts on your blog index and archive pages as you <a href='http://eviltrout.com/archives/' rel='nofollow'>can see here</a>. \n\nIt works with a similar API to embedding comments: \n\n <script type="text/javascript">\n var discourseUrl = "http://fishtank.eviltrout.com/";\n\n (function() {\n var d = document.createEleme…","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/b7797beb47cfb7aa0fe60d09604aaa09.png?s={size}&r=pg&d=identicon","slug":"discourse-plugin-for-static-site-generators-like-jekyll-or-octopress","topic_id":7965,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":98,"reply_to_post_number":null,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"zogstrip","acting_name":"Régis Hanol","acting_user_id":1995,"title":"Discourse plugin for static site generators like Jekyll or Octopress","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":2,"created_at":"2014-01-13T17:19:08Z","excerpt":"<a class='mention' href='/users/sam'>@Sam</a> do you have any idea why only some people are getting this issue? I dont' mind the proposed fix but I'd prefer to know why it happens in the first place.","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/5120fc4e345db0d1a964888272073819.png?s={size}&r=pg&d=identicon","slug":"error-after-update-to-0-9-8-1","topic_id":11903,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":10,"reply_to_post_number":null,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"riking","acting_name":"Kane York","acting_user_id":6626,"title":"Error after update to 0.9.8.1","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":2,"created_at":"2014-01-13T16:15:51Z","excerpt":"The code looks okay but it's hard to debug this way. \n\nOne thing you could do is add a: console.log('tracked!') just before line 8. Then open a developer console and see if the javascript is running properly.","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","slug":"support-for-piwik-analytics-as-an-alternative-to-google-analytics","topic_id":7512,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":18,"reply_to_post_number":16,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"codinghorror","acting_name":"Jeff Atwood","acting_user_id":32,"title":"Support for Piwik Analytics as an alternative to Google Analytics","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":2,"created_at":"2014-01-10T19:48:08Z","excerpt":"Thanks for letting us know. It turns out that by using minutely(5) instead of minutely causes ice_cube to peg a core at 100% usage. I've pushed out a fix in master.","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","slug":"sidekiq-cpu-load-since-latest-release","topic_id":9515,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":22,"reply_to_post_number":null,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"codinghorror","acting_name":"Jeff Atwood","acting_user_id":32,"title":"Sidekiq CPU load since latest release","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":2,"created_at":"2014-01-10T19:47:17Z","excerpt":"Thanks for letting us know. It turns out that by using minutely(5) instead of minutely causes ice_cube to peg a core at 100% usage. I've pushed out a fix in master.","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/42776c4982dff1fa45ee8248532f8ad0.png?s={size}&r=pg&d=identicon","slug":"sidekiq-cpu-load-since-latest-release","topic_id":9515,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":22,"reply_to_post_number":null,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"neil","acting_name":"Neil","acting_user_id":2,"title":"Sidekiq CPU load since latest release","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":2,"created_at":"2014-01-10T17:39:24Z","excerpt":"We should consider doing what Google Drive does: they intercept cmd-f and pop up a box that allows you to dynamically search.","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/5120fc4e345db0d1a964888272073819.png?s={size}&r=pg&d=identicon","slug":"ctrl-f-search-is-interrupted-by-quotation-popup","topic_id":7114,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":12,"reply_to_post_number":11,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"riking","acting_name":"Kane York","acting_user_id":6626,"title":"Ctrl+F search is interrupted by quotation popup","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":2,"created_at":"2014-01-10T17:29:15Z","excerpt":"Thanks for letting us know. It turns out that by using minutely(5) instead of minutely causes ice_cube to peg a core at 100% usage. I've pushed out a fix in master.","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/5120fc4e345db0d1a964888272073819.png?s={size}&r=pg&d=identicon","slug":"sidekiq-cpu-load-since-latest-release","topic_id":9515,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":22,"reply_to_post_number":null,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"riking","acting_name":"Kane York","acting_user_id":6626,"title":"Sidekiq CPU load since latest release","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":2,"created_at":"2014-01-10T17:24:37Z","excerpt":"Thanks for letting us know. It turns out that by using minutely(5) instead of minutely causes ice_cube to peg a core at 100% usage. I've pushed out a fix in master.","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/b7797beb47cfb7aa0fe60d09604aaa09.png?s={size}&r=pg&d=identicon","slug":"sidekiq-cpu-load-since-latest-release","topic_id":9515,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":22,"reply_to_post_number":null,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"zogstrip","acting_name":"Régis Hanol","acting_user_id":1995,"title":"Sidekiq CPU load since latest release","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":2,"created_at":"2014-01-10T16:58:12Z","excerpt":"Thanks for letting us know. It turns out that by using minutely(5) instead of minutely causes ice_cube to peg a core at 100% usage. I've pushed out a fix in master.","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//localhost:3000/uploads/default/avatars/527/614/d16e1504d9/{size}.jpg","slug":"sidekiq-cpu-load-since-latest-release","topic_id":9515,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":22,"reply_to_post_number":null,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"trident","acting_name":"Ben T","acting_user_id":5707,"title":"Sidekiq CPU load since latest release","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":2,"created_at":"2014-01-10T16:56:48Z","excerpt":"Thanks for letting us know. It turns out that by using minutely(5) instead of minutely causes ice_cube to peg a core at 100% usage. I've pushed out a fix in master.","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//localhost:3000/uploads/default/avatars/886/ea8/e533d87fd9/{size}.png","slug":"sidekiq-cpu-load-since-latest-release","topic_id":9515,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":22,"reply_to_post_number":null,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"michaeld","acting_name":"Michael","acting_user_id":6548,"title":"Sidekiq CPU load since latest release","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":2,"created_at":"2014-01-09T19:11:55Z","excerpt":"There is potentially good news on the horizon. One major improvement to Ember.js slated to come out this year is <a href='https://github.com/tildeio/htmlbars' rel='nofollow'>HTMLBars</a>. The basic idea is to use DOM based templates instead of string based ones. \n\nEarly benchmarks have been very promising. It seems to be much faster. Additionally, there is work b…","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/413ef976f0d2ca993005c9aee4769254.png?s={size}&r=pg&d=identicon","slug":"why-is-discourse-so-slow-on-android","topic_id":8823,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":64,"reply_to_post_number":null,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"BhaelOchon","acting_name":"Bill Ayakatubby","acting_user_id":471,"title":"Why is Discourse so slow on Android?","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":2,"created_at":"2014-01-09T18:28:52Z","excerpt":"There is potentially good news on the horizon. One major improvement to Ember.js slated to come out this year is <a href='https://github.com/tildeio/htmlbars' rel='nofollow'>HTMLBars</a>. The basic idea is to use DOM based templates instead of string based ones. \n\nEarly benchmarks have been very promising. It seems to be much faster. Additionally, there is work b…","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/b7797beb47cfb7aa0fe60d09604aaa09.png?s={size}&r=pg&d=identicon","slug":"why-is-discourse-so-slow-on-android","topic_id":8823,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":64,"reply_to_post_number":null,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"zogstrip","acting_name":"Régis Hanol","acting_user_id":1995,"title":"Why is Discourse so slow on Android?","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":2,"created_at":"2014-01-07T11:46:52Z","excerpt":"We should consider doing what Google Drive does: they intercept cmd-f and pop up a box that allows you to dynamically search.","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/f14e2f41c74347c49889cd87188e68b7.png?s={size}&r=pg&d=identicon","slug":"ctrl-f-search-is-interrupted-by-quotation-popup","topic_id":7114,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":12,"reply_to_post_number":11,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"dgw","acting_name":"dgw","acting_user_id":3169,"title":"Ctrl+F search is interrupted by quotation popup","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":2,"created_at":"2014-01-03T23:42:29Z","excerpt":"I've pushed out some updates to this feature after reviewing it with the Discourse team. \n\n\nInstead of the best posts, it now shows all (up to a user configurable limit of 100.)\nIt shows a total of how many posts there are\nIf a post has replies or is in reply it says so\nLong usernames are broken up …","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//localhost:3000/uploads/default/avatars/527/614/d16e1504d9/{size}.jpg","slug":"discourse-plugin-for-static-site-generators-like-jekyll-or-octopress","topic_id":7965,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":91,"reply_to_post_number":90,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"trident","acting_name":"Ben T","acting_user_id":5707,"title":"Discourse plugin for static site generators like Jekyll or Octopress","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":2,"created_at":"2014-01-03T23:24:23Z","excerpt":"I've pushed out some updates to this feature after reviewing it with the Discourse team. \n\n\nInstead of the best posts, it now shows all (up to a user configurable limit of 100.)\nIt shows a total of how many posts there are\nIf a post has replies or is in reply it says so\nLong usernames are broken up …","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/69fda0df8b4878fb6a18deffa972d26a.png?s={size}&r=pg&d=identicon","slug":"discourse-plugin-for-static-site-generators-like-jekyll-or-octopress","topic_id":7965,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":91,"reply_to_post_number":90,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"erlend_sh","acting_name":"Erlend Sogge Heggen","acting_user_id":5351,"title":"Discourse plugin for static site generators like Jekyll or Octopress","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":2,"created_at":"2014-01-03T21:26:52Z","excerpt":"I've pushed out some updates to this feature after reviewing it with the Discourse team. \n\n\nInstead of the best posts, it now shows all (up to a user configurable limit of 100.)\nIt shows a total of how many posts there are\nIf a post has replies or is in reply it says so\nLong usernames are broken up …","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","slug":"discourse-plugin-for-static-site-generators-like-jekyll-or-octopress","topic_id":7965,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":91,"reply_to_post_number":90,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"codinghorror","acting_name":"Jeff Atwood","acting_user_id":32,"title":"Discourse plugin for static site generators like Jekyll or Octopress","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":2,"created_at":"2014-01-03T19:59:26Z","excerpt":"I've pushed out some updates to this feature after reviewing it with the Discourse team. \n\n\nInstead of the best posts, it now shows all (up to a user configurable limit of 100.)\nIt shows a total of how many posts there are\nIf a post has replies or is in reply it says so\nLong usernames are broken up …","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/5120fc4e345db0d1a964888272073819.png?s={size}&r=pg&d=identicon","slug":"discourse-plugin-for-static-site-generators-like-jekyll-or-octopress","topic_id":7965,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":91,"reply_to_post_number":90,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"riking","acting_name":"Kane York","acting_user_id":6626,"title":"Discourse plugin for static site generators like Jekyll or Octopress","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":2,"created_at":"2014-01-03T18:39:26Z","excerpt":"I've pushed out some updates to this feature after reviewing it with the Discourse team. \n\n\nInstead of the best posts, it now shows all (up to a user configurable limit of 100.)\nIt shows a total of how many posts there are\nIf a post has replies or is in reply it says so\nLong usernames are broken up …","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/82c793022ec1bce6ea7573bc27b2340b.png?s={size}&r=pg&d=identicon","slug":"discourse-plugin-for-static-site-generators-like-jekyll-or-octopress","topic_id":7965,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":91,"reply_to_post_number":90,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"PabloC","acting_name":"Pablo Corral","acting_user_id":2291,"title":"Discourse plugin for static site generators like Jekyll or Octopress","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":2,"created_at":"2014-01-03T18:25:00Z","excerpt":"I've pushed out some updates to this feature after reviewing it with the Discourse team. \n\n\nInstead of the best posts, it now shows all (up to a user configurable limit of 100.)\nIt shows a total of how many posts there are\nIf a post has replies or is in reply it says so\nLong usernames are broken up …","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/b7797beb47cfb7aa0fe60d09604aaa09.png?s={size}&r=pg&d=identicon","slug":"discourse-plugin-for-static-site-generators-like-jekyll-or-octopress","topic_id":7965,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":91,"reply_to_post_number":90,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"zogstrip","acting_name":"Régis Hanol","acting_user_id":1995,"title":"Discourse plugin for static site generators like Jekyll or Octopress","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":2,"created_at":"2014-01-02T22:04:40Z","excerpt":"It's my last commit before the new year [wine_glass][beers] so I wanted it to be a good one. I just deployed the ability to embed Discourse into static sites. You can see it working on my <a href='http://eviltrout.com/2013/11/24/i18n-in-ember.html#discourse-comments' rel='nofollow'>blog here</a>. \n\nIn few days I'll write in detail how it works and how to set it up, but the jist of it is to includ…","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/038e2caac4482e97ba6b24c3a88b86ff.png?s={size}&r=pg&d=identicon","slug":"discourse-plugin-for-static-site-generators-like-jekyll-or-octopress","topic_id":7965,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":85,"reply_to_post_number":null,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"lightyear","acting_name":"Benjamin Kampmann","acting_user_id":6060,"title":"Discourse plugin for static site generators like Jekyll or Octopress","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":2,"created_at":"2014-01-02T21:44:55Z","excerpt":"I had no end of problems with animations. On desktop Chrome they work fine, but many mobile browsers and such get awful performance and weird behaviour. I ended up stripping most of them while we got the site working across the board. I wouldn't be against adding some in, but maybe we should plugini…","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/5120fc4e345db0d1a964888272073819.png?s={size}&r=pg&d=identicon","slug":"click-top-bar-to-scroll-top","topic_id":11655,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":16,"reply_to_post_number":8,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"riking","acting_name":"Kane York","acting_user_id":6626,"title":"Click top bar to scroll top","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":2,"created_at":"2014-01-02T21:42:54Z","excerpt":"Okay, I have a fix here for the feed crawler: \n\n<a href='https://github.com/discourse/discourse/commit/ed2e53bb068246205e2c3fc1fd985a54859fcad7' target='_blank'>https://github.com/discourse/discourse/commit/ed2e53bb068246205e2c3fc1fd985a54859fcad7</a>","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//localhost:3000/uploads/default/avatars/527/614/d16e1504d9/{size}.jpg","slug":"discourse-plugin-for-static-site-generators-like-jekyll-or-octopress","topic_id":7965,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":89,"reply_to_post_number":87,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"trident","acting_name":"Ben T","acting_user_id":5707,"title":"Discourse plugin for static site generators like Jekyll or Octopress","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":2,"created_at":"2014-01-02T21:41:43Z","excerpt":"Okay I've pushed a fix for admins / topic creators: \n\n<a href='https://github.com/discourse/discourse/commit/1478f08e4fe102b79978fa51b7846c85ff3f7c74' target='_blank'>https://github.com/discourse/discourse/commit/1478f08e4fe102b79978fa51b7846c85ff3f7c74</a>","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","slug":"what-is-the-point-of-limiting-new-users-to-three-replies-per-topic","topic_id":11696,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":13,"reply_to_post_number":null,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"codinghorror","acting_name":"Jeff Atwood","acting_user_id":32,"title":"What is the point of limiting new users to three replies per topic?","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":2,"created_at":"2014-01-02T04:01:57Z","excerpt":"Over the weekend, <a class='mention' href='/users/zogstrip'>@zogstrip</a> and I created a plugin to use the excellent <a href='http://joshbuddy.github.io/spoiler-alert/' rel='nofollow'>Spoiler Alert</a> plugin to super power our [spoiler] tag support. Check it out on github! \n\n<a href='https://github.com/discourse/discourse-spoiler-alert' class='onebox' target='_blank' rel='nofollow'>https://github.com/discourse/discourse-spoiler-alert</a>","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/09f42309d5312962e4ca300ba4ff37fa.png?s={size}&r=pg&d=identicon","slug":"brand-new-plugin-interface","topic_id":8793,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":44,"reply_to_post_number":null,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"DavidGNavas","acting_name":"David García-Navas","acting_user_id":7229,"title":"Brand new plugin interface","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":2,"created_at":"2014-01-01T19:25:38Z","excerpt":"It's my last commit before the new year [wine_glass][beers] so I wanted it to be a good one. I just deployed the ability to embed Discourse into static sites. You can see it working on my <a href='http://eviltrout.com/2013/11/24/i18n-in-ember.html#discourse-comments' rel='nofollow'>blog here</a>. \n\nIn few days I'll write in detail how it works and how to set it up, but the jist of it is to includ…","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","slug":"discourse-plugin-for-static-site-generators-like-jekyll-or-octopress","topic_id":7965,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":85,"reply_to_post_number":null,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"codinghorror","acting_name":"Jeff Atwood","acting_user_id":32,"title":"Discourse plugin for static site generators like Jekyll or Octopress","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":2,"created_at":"2014-01-01T10:19:15Z","excerpt":"It's my last commit before the new year [wine_glass][beers] so I wanted it to be a good one. I just deployed the ability to embed Discourse into static sites. You can see it working on my <a href='http://eviltrout.com/2013/11/24/i18n-in-ember.html#discourse-comments' rel='nofollow'>blog here</a>. \n\nIn few days I'll write in detail how it works and how to set it up, but the jist of it is to includ…","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/69fda0df8b4878fb6a18deffa972d26a.png?s={size}&r=pg&d=identicon","slug":"discourse-plugin-for-static-site-generators-like-jekyll-or-octopress","topic_id":7965,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":85,"reply_to_post_number":null,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"erlend_sh","acting_name":"Erlend Sogge Heggen","acting_user_id":5351,"title":"Discourse plugin for static site generators like Jekyll or Octopress","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":2,"created_at":"2014-01-01T06:45:25Z","excerpt":"It's my last commit before the new year [wine_glass][beers] so I wanted it to be a good one. I just deployed the ability to embed Discourse into static sites. You can see it working on my <a href='http://eviltrout.com/2013/11/24/i18n-in-ember.html#discourse-comments' rel='nofollow'>blog here</a>. \n\nIn few days I'll write in detail how it works and how to set it up, but the jist of it is to includ…","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//localhost:3000/uploads/default/avatars/95a/06d/c337428568/{size}.png","slug":"discourse-plugin-for-static-site-generators-like-jekyll-or-octopress","topic_id":7965,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":85,"reply_to_post_number":null,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"Lee_Ars","acting_name":"Lee_Ars","acting_user_id":4457,"title":"Discourse plugin for static site generators like Jekyll or Octopress","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":2,"created_at":"2014-01-01T02:37:01Z","excerpt":"It's my last commit before the new year [wine_glass][beers] so I wanted it to be a good one. I just deployed the ability to embed Discourse into static sites. You can see it working on my <a href='http://eviltrout.com/2013/11/24/i18n-in-ember.html#discourse-comments' rel='nofollow'>blog here</a>. \n\nIn few days I'll write in detail how it works and how to set it up, but the jist of it is to includ…","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//localhost:3000/uploads/default/avatars/527/614/d16e1504d9/{size}.jpg","slug":"discourse-plugin-for-static-site-generators-like-jekyll-or-octopress","topic_id":7965,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":85,"reply_to_post_number":null,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"trident","acting_name":"Ben T","acting_user_id":5707,"title":"Discourse plugin for static site generators like Jekyll or Octopress","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":2,"created_at":"2014-01-01T01:10:00Z","excerpt":"It's my last commit before the new year [wine_glass][beers] so I wanted it to be a good one. I just deployed the ability to embed Discourse into static sites. You can see it working on my <a href='http://eviltrout.com/2013/11/24/i18n-in-ember.html#discourse-comments' rel='nofollow'>blog here</a>. \n\nIn few days I'll write in detail how it works and how to set it up, but the jist of it is to includ…","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/b7797beb47cfb7aa0fe60d09604aaa09.png?s={size}&r=pg&d=identicon","slug":"discourse-plugin-for-static-site-generators-like-jekyll-or-octopress","topic_id":7965,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":85,"reply_to_post_number":null,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"zogstrip","acting_name":"Régis Hanol","acting_user_id":1995,"title":"Discourse plugin for static site generators like Jekyll or Octopress","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":2,"created_at":"2013-12-24T18:44:52Z","excerpt":"I agree about performance being a core value, but how does showing numbers to non-developers help? They won't understand them nor know what they mean or how to interpret them. It just ends up being clutter that they ignore. \n\nThis isn't the first person who's asked how to remove it.","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/c062c74a11a5281e22a7f90fd080f3f1.png?s={size}&r=pg&d=identicon","slug":"performance-times","topic_id":11567,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":7,"reply_to_post_number":6,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"SneakySly","acting_name":"Anthony Giovannetti","acting_user_id":5048,"title":"Performance Times","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":2,"created_at":"2013-12-24T18:44:10Z","excerpt":"<a class='mention' href='/users/sam'>@sam</a> as awesome as mini profiler is, I think we should consider turning it off by default. Most admins running discourse sites won't care about performance statistics and those who do can easily turn it on. Thoughts?","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/c062c74a11a5281e22a7f90fd080f3f1.png?s={size}&r=pg&d=identicon","slug":"performance-times","topic_id":11567,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":2,"reply_to_post_number":null,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"SneakySly","acting_name":"Anthony Giovannetti","acting_user_id":5048,"title":"Performance Times","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":2,"created_at":"2013-12-24T16:27:22Z","excerpt":"I've deployed a fix to this. It removes rows from our whitelisted attributes, because I can't imagine a user ever needing that in a post [smile]","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/aedbd784f8a5013f527ce103aa1d3cc1.png?s={size}&r=pg&d=identicon","slug":"1-billion-rows-breaks-stuff","topic_id":11564,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":5,"reply_to_post_number":null,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"YOU","acting_name":"YOU","acting_user_id":7731,"title":"1 Billion Rows BREAKS stuff","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":2,"created_at":"2013-12-23T23:34:42Z","excerpt":"I've deployed a fix to this. It removes rows from our whitelisted attributes, because I can't imagine a user ever needing that in a post [smile]","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/5120fc4e345db0d1a964888272073819.png?s={size}&r=pg&d=identicon","slug":"1-billion-rows-breaks-stuff","topic_id":11564,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":5,"reply_to_post_number":null,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"riking","acting_name":"Kane York","acting_user_id":6626,"title":"1 Billion Rows BREAKS stuff","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":2,"created_at":"2013-12-23T23:33:45Z","excerpt":"I've deployed a fix to this. It removes rows from our whitelisted attributes, because I can't imagine a user ever needing that in a post [smile]","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/b7797beb47cfb7aa0fe60d09604aaa09.png?s={size}&r=pg&d=identicon","slug":"1-billion-rows-breaks-stuff","topic_id":11564,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":5,"reply_to_post_number":null,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"zogstrip","acting_name":"Régis Hanol","acting_user_id":1995,"title":"1 Billion Rows BREAKS stuff","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":2,"created_at":"2013-12-23T22:26:36Z","excerpt":"<a class='mention' href='/users/sam'>@sam</a> as awesome as mini profiler is, I think we should consider turning it off by default. Most admins running discourse sites won't care about performance statistics and those who do can easily turn it on. Thoughts?","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/69fda0df8b4878fb6a18deffa972d26a.png?s={size}&r=pg&d=identicon","slug":"performance-times","topic_id":11567,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":2,"reply_to_post_number":null,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"erlend_sh","acting_name":"Erlend Sogge Heggen","acting_user_id":5351,"title":"Performance Times","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":2,"created_at":"2013-12-23T22:20:31Z","excerpt":"I'm covering for <a class='mention' href='/users/neil'>@Neil</a> who is off for the holidays. It looks like Googlebot was parsing our Javascript as that's the only place where the string occurs. I added an extra check to not display that message to Googlebot and hopefully that will fix the problem. We'll have to keep an eye on it for a bit …","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","slug":"google-search-results-issue-with-forums-powered-by-discourse","topic_id":11565,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":3,"reply_to_post_number":null,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"codinghorror","acting_name":"Jeff Atwood","acting_user_id":32,"title":"Google search results issue with forums powered by Discourse","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":2,"created_at":"2013-12-23T21:38:31Z","excerpt":"We should also consider putting it into a plugin. Perhaps a developer plugin combined with <a href='https://github.com/eviltrout/ember-renderspeed' rel='nofollow'>ember-renderspeed</a> and anything else we use for debugging.","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/20c057f893dc884e455f8c6798bda75b.png?s={size}&r=pg&d=identicon","slug":"performance-times","topic_id":11567,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":5,"reply_to_post_number":4,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"illspirit","acting_name":"Jacob","acting_user_id":6695,"title":"Performance Times","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":2,"created_at":"2013-12-23T21:38:23Z","excerpt":"<a class='mention' href='/users/sam'>@sam</a> as awesome as mini profiler is, I think we should consider turning it off by default. Most admins running discourse sites won't care about performance statistics and those who do can easily turn it on. Thoughts?","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/20c057f893dc884e455f8c6798bda75b.png?s={size}&r=pg&d=identicon","slug":"performance-times","topic_id":11567,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":2,"reply_to_post_number":null,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"illspirit","acting_name":"Jacob","acting_user_id":6695,"title":"Performance Times","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":2,"created_at":"2013-12-23T20:45:38Z","excerpt":"We should also consider putting it into a plugin. Perhaps a developer plugin combined with <a href='https://github.com/eviltrout/ember-renderspeed' rel='nofollow'>ember-renderspeed</a> and anything else we use for debugging.","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/b7797beb47cfb7aa0fe60d09604aaa09.png?s={size}&r=pg&d=identicon","slug":"performance-times","topic_id":11567,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":5,"reply_to_post_number":4,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"zogstrip","acting_name":"Régis Hanol","acting_user_id":1995,"title":"Performance Times","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":2,"created_at":"2013-12-23T20:43:16Z","excerpt":"I'm covering for <a class='mention' href='/users/neil'>@Neil</a> who is off for the holidays. It looks like Googlebot was parsing our Javascript as that's the only place where the string occurs. I added an extra check to not display that message to Googlebot and hopefully that will fix the problem. We'll have to keep an eye on it for a bit …","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/b7797beb47cfb7aa0fe60d09604aaa09.png?s={size}&r=pg&d=identicon","slug":"google-search-results-issue-with-forums-powered-by-discourse","topic_id":11565,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":3,"reply_to_post_number":null,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"zogstrip","acting_name":"Régis Hanol","acting_user_id":1995,"title":"Google search results issue with forums powered by Discourse","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":2,"created_at":"2013-12-21T20:19:42Z","excerpt":"It's a bit tricky if it's your first plugin but here's how you'd do it. \n\n (function() {\n\n Discourse.Route.buildRoutes(function() {\n this.route('signup', {path: '/signup'});\n });\n\n Discourse.SignupRoute = Discourse.Route.extend({\n beforeModel: function() {\n this.transitionTo('list.late…","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/1eb9fb4ff9cc03087229f202103f1d31.png?s={size}&r=pg&d=identicon","slug":"plugin-to-make-signup-modal-pop-up-at-a-route","topic_id":11486,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":5,"reply_to_post_number":4,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"williscool","acting_name":"will","acting_user_id":7495,"title":"Plugin to make signup modal pop up at a route","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":2,"created_at":"2013-12-21T09:26:11Z","excerpt":"This should be fixed now, sorry!","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/48b465ea4a935f74ad3711211b3f1ed8.png?s={size}&r=pg&d=identicon","slug":"why-is-there-a-topic-reply-limit-for-new-users","topic_id":11513,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":8,"reply_to_post_number":7,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"npruehs","acting_name":"npruehs","acting_user_id":7959,"title":"Why is there a topic reply limit for new users?","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":2,"created_at":"2013-12-21T05:26:10Z","excerpt":"It's a bit tricky if it's your first plugin but here's how you'd do it. \n\n (function() {\n\n Discourse.Route.buildRoutes(function() {\n this.route('signup', {path: '/signup'});\n });\n\n Discourse.SignupRoute = Discourse.Route.extend({\n beforeModel: function() {\n this.transitionTo('list.late…","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/5120fc4e345db0d1a964888272073819.png?s={size}&r=pg&d=identicon","slug":"plugin-to-make-signup-modal-pop-up-at-a-route","topic_id":11486,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":5,"reply_to_post_number":4,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"riking","acting_name":"Kane York","acting_user_id":6626,"title":"Plugin to make signup modal pop up at a route","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":2,"created_at":"2013-12-20T22:42:16Z","excerpt":"I just tried on iOS 7.0.3 and 7.0.4 on the iPad 4 and iOS simulator, and both seem to work fine. Is there anything special you need to do besides use portrait mode in that topic? Do you scroll quickly or slowly? Does it always happen or just sometimes? \n\nedit: <a class='mention' href='/users/codinghorror'>@codinghorror</a> helped me figure it out. …","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/b7797beb47cfb7aa0fe60d09604aaa09.png?s={size}&r=pg&d=identicon","slug":"ipad-portrait-mode-scrolling-stops-at-the-19th-post","topic_id":11524,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":5,"reply_to_post_number":4,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"zogstrip","acting_name":"Régis Hanol","acting_user_id":1995,"title":"iPad, portrait mode: scrolling stops at the 19th post","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":2,"created_at":"2013-12-20T19:21:02Z","excerpt":"This should be fixed now, sorry!","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","slug":"why-is-there-a-topic-reply-limit-for-new-users","topic_id":11513,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":8,"reply_to_post_number":7,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"codinghorror","acting_name":"Jeff Atwood","acting_user_id":32,"title":"Why is there a topic reply limit for new users?","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":2,"created_at":"2013-12-20T18:49:53Z","excerpt":"It's a bit tricky if it's your first plugin but here's how you'd do it. \n\n (function() {\n\n Discourse.Route.buildRoutes(function() {\n this.route('signup', {path: '/signup'});\n });\n\n Discourse.SignupRoute = Discourse.Route.extend({\n beforeModel: function() {\n this.transitionTo('list.late…","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//localhost:3000/uploads/default/avatars/a77/160/c978adf6ab/{size}.jpg","slug":"plugin-to-make-signup-modal-pop-up-at-a-route","topic_id":11486,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":5,"reply_to_post_number":4,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"timpone","acting_name":"jon","acting_user_id":3687,"title":"Plugin to make signup modal pop up at a route","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":2,"created_at":"2013-12-20T17:59:37Z","excerpt":"This should be fixed now, sorry!","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/b7797beb47cfb7aa0fe60d09604aaa09.png?s={size}&r=pg&d=identicon","slug":"why-is-there-a-topic-reply-limit-for-new-users","topic_id":11513,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":8,"reply_to_post_number":7,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"zogstrip","acting_name":"Régis Hanol","acting_user_id":1995,"title":"Why is there a topic reply limit for new users?","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":2,"created_at":"2013-12-20T16:43:05Z","excerpt":"It's a bit tricky if it's your first plugin but here's how you'd do it. \n\n (function() {\n\n Discourse.Route.buildRoutes(function() {\n this.route('signup', {path: '/signup'});\n });\n\n Discourse.SignupRoute = Discourse.Route.extend({\n beforeModel: function() {\n this.transitionTo('list.late…","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/b7797beb47cfb7aa0fe60d09604aaa09.png?s={size}&r=pg&d=identicon","slug":"plugin-to-make-signup-modal-pop-up-at-a-route","topic_id":11486,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":5,"reply_to_post_number":4,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"zogstrip","acting_name":"Régis Hanol","acting_user_id":1995,"title":"Plugin to make signup modal pop up at a route","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null}]}; -Discourse.URL_FIXTURES["/user_actions.json?offset=0&username=eviltrout&filter=11"] = {"user_actions":[{"action_type":11,"created_at":"2013-12-30T23:35:09Z","excerpt":"It's only for new users to prevent spam. You will quickly graduate to basic user if you have good habits and the limit goes away. \n\nIf you don't like it on your forum, you can just increase the maximum in the site settings to a really high number.","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/3dcae8378d46c244172a115c28ca49ce.png?s={size}&r=pg&d=identicon","slug":"limiting-number-of-posts-on-a-new-users-first-day","topic_id":11667,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":3,"reply_to_post_number":null,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"sam","acting_name":"Sam Saffron","acting_user_id":1,"title":"Limiting number of posts on a new user's first day","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":""},{"action_type":11,"created_at":"2013-09-13T08:47:36Z","excerpt":"Here's an example from our code base. Here's the current test: \n\n test("canDeleteSpammer not staff", function(){\n var flagCon = testController(Discourse.FlagController, buildPost());\n this.stub(Discourse.User, 'currentProp').withArgs('staff').returns(false);\n flagCon.set('selected', Discourse.Pos…","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/3dcae8378d46c244172a115c28ca49ce.png?s={size}&r=pg&d=identicon","slug":"reverted-dependency-injection-pr","topic_id":9717,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":8,"reply_to_post_number":6,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"sam","acting_name":"Sam Saffron","acting_user_id":1,"title":"Reverted dependency injection PR","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":11,"created_at":"2013-08-02T22:29:25Z","excerpt":"Ember Patches\n\nA few of the improvements I've made were technical changes to <a href='http://emberjs.com/' rel='nofollow'>Ember.js</a>. I'll be creating detailed pull requests for each one to see if the core team finds them sane and is willing to integrate them. The good news is we've been running most of them for a few days with no major reported…","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","slug":"why-is-discourse-so-slow-on-android","topic_id":8823,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":8,"reply_to_post_number":null,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"codinghorror","acting_name":"Jeff Atwood","acting_user_id":32,"title":"Why is Discourse so slow on Android?","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":11,"created_at":"2013-06-25T16:19:52Z","excerpt":"We've just enabled the ability to reply by email to Discourse for all users on meta! It works like on other sites such as Facebook or Github. If an email is related to a topic, it will say in the footer that you can reply to it. Simply reply to the message in your email client and your post will be …","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","slug":"new-reply-via-email-support","topic_id":7764,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":1,"reply_to_post_number":null,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"codinghorror","acting_name":"Jeff Atwood","acting_user_id":32,"title":"New: Reply via Email Support!","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":11,"created_at":"2013-02-13T00:56:51Z","excerpt":"I've just deployed some slightly better documentation to our project regarding developer set ups. Vagrant is still the recommended install for most people, however if you have Rails experience there is now an <a href='https://github.com/discourse/discourse/blob/master/docs/DEVELOPER-ADVANCED.md' rel='nofollow'>advanced guide</a>. The advanced guide also contains instructions on setting up your own Vagran…","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","slug":"new-updated-docs","topic_id":2918,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":1,"reply_to_post_number":null,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"codinghorror","acting_name":"Jeff Atwood","acting_user_id":32,"title":"New: Updated Docs","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null}]}; +Discourse.URL_FIXTURES["/user_actions.json?offset=0&username=eviltrout&filter=11"] = {"user_actions":[{"action_type":11,"created_at":"2013-12-30T23:35:09Z","excerpt":"It's only for new users to prevent spam. You will quickly graduate to basic user if you have good habits and the limit goes away. \n\nIf you don't like it on your forum, you can just increase the maximum in the site settings to a really high number.","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/3dcae8378d46c244172a115c28ca49ce.png?s={size}&r=pg&d=identicon","slug":"limiting-number-of-posts-on-a-new-users-first-day","topic_id":11667,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":3,"reply_to_post_number":null,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"sam","acting_name":"Sam Saffron","acting_user_id":1,"title":"Limiting number of posts on a new user's first day","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":""},{"action_type":11,"created_at":"2013-09-13T08:47:36Z","excerpt":"Here's an example from our code base. Here's the current test: \n\n test("canDeleteSpammer not staff", function(){\n var flagCon = testController(Discourse.FlagController, buildPost());\n sandbox.stub(Discourse.User, 'currentProp').withArgs('staff').returns(false);\n flagCon.set('selected', Discourse.Pos…","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/3dcae8378d46c244172a115c28ca49ce.png?s={size}&r=pg&d=identicon","slug":"reverted-dependency-injection-pr","topic_id":9717,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":8,"reply_to_post_number":6,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"sam","acting_name":"Sam Saffron","acting_user_id":1,"title":"Reverted dependency injection PR","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":11,"created_at":"2013-08-02T22:29:25Z","excerpt":"Ember Patches\n\nA few of the improvements I've made were technical changes to <a href='http://emberjs.com/' rel='nofollow'>Ember.js</a>. I'll be creating detailed pull requests for each one to see if the core team finds them sane and is willing to integrate them. The good news is we've been running most of them for a few days with no major reported…","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","slug":"why-is-discourse-so-slow-on-android","topic_id":8823,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":8,"reply_to_post_number":null,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"codinghorror","acting_name":"Jeff Atwood","acting_user_id":32,"title":"Why is Discourse so slow on Android?","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":11,"created_at":"2013-06-25T16:19:52Z","excerpt":"We've just enabled the ability to reply by email to Discourse for all users on meta! It works like on other sites such as Facebook or Github. If an email is related to a topic, it will say in the footer that you can reply to it. Simply reply to the message in your email client and your post will be …","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","slug":"new-reply-via-email-support","topic_id":7764,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":1,"reply_to_post_number":null,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"codinghorror","acting_name":"Jeff Atwood","acting_user_id":32,"title":"New: Reply via Email Support!","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null},{"action_type":11,"created_at":"2013-02-13T00:56:51Z","excerpt":"I've just deployed some slightly better documentation to our project regarding developer set ups. Vagrant is still the recommended install for most people, however if you have Rails experience there is now an <a href='https://github.com/discourse/discourse/blob/master/docs/DEVELOPER-ADVANCED.md' rel='nofollow'>advanced guide</a>. The advanced guide also contains instructions on setting up your own Vagran…","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","acting_avatar_template":"//www.gravatar.com/avatar/51d623f33f8b83095db84ff35e15dbe8.png?s={size}&r=pg&d=identicon","slug":"new-updated-docs","topic_id":2918,"target_user_id":19,"target_name":"Robin Ward","target_username":"eviltrout","post_number":1,"reply_to_post_number":null,"username":"eviltrout","name":"Robin Ward","user_id":19,"acting_username":"codinghorror","acting_name":"Jeff Atwood","acting_user_id":32,"title":"New: Updated Docs","deleted":false,"hidden":false,"moderator_action":false,"edit_reason":null}]}; diff --git a/test/javascripts/helpers/parse_html.js b/test/javascripts/helpers/parse_html.js index 4c15c9826..a451ffb01 100644 --- a/test/javascripts/helpers/parse_html.js +++ b/test/javascripts/helpers/parse_html.js @@ -6,4 +6,4 @@ function parseHTML(rawHtml) { parser.parseComplete(rawHtml); return builder.dom; -} \ No newline at end of file +} diff --git a/test/javascripts/helpers/qunit_helpers.js b/test/javascripts/helpers/qunit_helpers.js index 55bbef322..80f875fbc 100644 --- a/test/javascripts/helpers/qunit_helpers.js +++ b/test/javascripts/helpers/qunit_helpers.js @@ -1,17 +1,13 @@ -/* global asyncTest, requirejs, require */ +/* global asyncTest */ /* exported integration, testController, controllerFor, asyncTestDiscourse, fixture */ - - function integration(name, lifecycle) { module("Integration: " + name, { setup: function() { - sinon.stub(Discourse.ScrollingDOMMethods, "bindOnScroll"); - sinon.stub(Discourse.ScrollingDOMMethods, "unbindOnScroll"); Ember.run(Discourse, Discourse.advanceReadiness); - if (lifecycle && lifecycle.setup) { lifecycle.setup.call(this); } + Discourse.reset(); }, teardown: function() { @@ -20,8 +16,6 @@ function integration(name, lifecycle) { } Discourse.reset(); - Discourse.ScrollingDOMMethods.bindOnScroll.restore(); - Discourse.ScrollingDOMMethods.unbindOnScroll.restore(); } }); } @@ -32,14 +26,6 @@ function controllerFor(controller, model) { return controller; } -function viewClassFor(name) { - return Discourse.__container__.lookupFactory('view:' + name); -} - -function componentClassFor(name) { - return Discourse.__container__.lookupFactory('component:' + name); -} - function asyncTestDiscourse(text, func) { asyncTest(text, function () { var self = this; diff --git a/test/javascripts/integration/header-test.js b/test/javascripts/integration/header-test.js index e5db4d1b3..4ee6239da 100644 --- a/test/javascripts/integration/header-test.js +++ b/test/javascripts/integration/header-test.js @@ -1,7 +1,7 @@ integration("Header", { setup: function() { var originalUser = Discourse.User.current(); - sinon.stub(Discourse.User, "current").returns(originalUser); + sandbox.stub(Discourse.User, "current").returns(originalUser); Discourse.User.current.returns(Ember.Object.create({ username: 'test', staff: true, @@ -29,7 +29,7 @@ test("header", function() { // Logo changing andThen(function() { - controllerFor("header").set("showExtraInfo", true); + controllerFor('header').set("showExtraInfo", true); }); andThen(function() { diff --git a/test/javascripts/lib/click_track_test.js b/test/javascripts/lib/click_track_test.js index 25be417f2..82f7348bd 100644 --- a/test/javascripts/lib/click_track_test.js +++ b/test/javascripts/lib/click_track_test.js @@ -1,12 +1,16 @@ +var windowOpen, + win, + redirectTo; + module("Discourse.ClickTrack", { setup: function() { // Prevent any of these tests from navigating away - this.win = {focus: function() { } }; - this.redirectTo = sinon.stub(Discourse.URL, "redirectTo"); - sinon.stub(Discourse, "ajax"); - this.windowOpen = sinon.stub(window, "open").returns(this.win); - sinon.stub(this.win, "focus"); + win = {focus: function() { } }; + redirectTo = sandbox.stub(Discourse.URL, "redirectTo"); + sandbox.stub(Discourse, "ajax"); + windowOpen = sandbox.stub(window, "open").returns(win); + sandbox.stub(win, "focus"); fixture().html([ '<div id="topic" id="1337">', @@ -23,13 +27,6 @@ module("Discourse.ClickTrack", { ' <a class="attachment" href="http://discuss.domain.com/uploads/default/1234/1532357280.txt">log.txt</a>', ' </article>', '</div>'].join("\n")); - }, - - teardown: function() { - Discourse.URL.redirectTo.restore(); - Discourse.ajax.restore(); - window.open.restore(); - this.win.focus.restore(); } }); @@ -42,14 +39,14 @@ var generateClickEventOn = function(selector) { test("does not track clicks on lightboxes", function() { var clickEvent = generateClickEventOn('.lightbox'); - this.stub(clickEvent, "preventDefault"); + sandbox.stub(clickEvent, "preventDefault"); ok(track(clickEvent)); ok(!clickEvent.preventDefault.calledOnce); }); test("it calls preventDefault when clicking on an a", function() { var clickEvent = generateClickEventOn('a'); - this.stub(clickEvent, "preventDefault"); + sandbox.stub(clickEvent, "preventDefault"); track(clickEvent); ok(clickEvent.preventDefault.calledOnce); ok(Discourse.URL.redirectTo.calledOnce); @@ -82,12 +79,12 @@ var badgeClickCount = function(id, expected) { }; test("does not update badge clicks on my own link", function() { - this.stub(Discourse.User, 'currentProp').withArgs('id').returns(314); + sandbox.stub(Discourse.User, 'currentProp').withArgs('id').returns(314); badgeClickCount('with-badge', 1); }); test("does not update badge clicks in my own post", function() { - this.stub(Discourse.User, 'currentProp').withArgs('id').returns(3141); + sandbox.stub(Discourse.User, 'currentProp').withArgs('id').returns(3141); badgeClickCount('with-badge-but-not-mine', 1); }); @@ -117,7 +114,7 @@ test("right clicks are tracked", function() { test("preventDefault is not called for right clicks", function() { var clickEvent = generateClickEventOn('a'); clickEvent.which = 3; - this.stub(clickEvent, "preventDefault"); + sandbox.stub(clickEvent, "preventDefault"); ok(track(clickEvent)); ok(!clickEvent.preventDefault.calledOnce); }); @@ -126,7 +123,7 @@ var testOpenInANewTab = function(description, clickEventModifier) { test(description, function() { var clickEvent = generateClickEventOn('a'); clickEventModifier(clickEvent); - this.stub(clickEvent, "preventDefault"); + sandbox.stub(clickEvent, "preventDefault"); ok(track(clickEvent)); ok(Discourse.ajax.calledOnce); ok(!clickEvent.preventDefault.calledOnce); @@ -150,8 +147,8 @@ testOpenInANewTab("it opens in a new tab on middle click", function(clickEvent) }); test("tracks via AJAX if we're on the same site", function() { - this.stub(Discourse.URL, "routeTo"); - this.stub(Discourse.URL, "origin").returns("http://discuss.domain.com"); + sandbox.stub(Discourse.URL, "routeTo"); + sandbox.stub(Discourse.URL, "origin").returns("http://discuss.domain.com"); ok(!track(generateClickEventOn('#same-site'))); ok(Discourse.ajax.calledOnce); @@ -159,8 +156,8 @@ test("tracks via AJAX if we're on the same site", function() { }); test("does not track via AJAX for attachments", function() { - this.stub(Discourse.URL, "routeTo"); - this.stub(Discourse.URL, "origin").returns("http://discuss.domain.com"); + sandbox.stub(Discourse.URL, "routeTo"); + sandbox.stub(Discourse.URL, "origin").returns("http://discuss.domain.com"); ok(!track(generateClickEventOn('.attachment'))); ok(Discourse.URL.redirectTo.calledOnce); @@ -168,13 +165,13 @@ test("does not track via AJAX for attachments", function() { test("tracks custom urls when opening in another window", function() { var clickEvent = generateClickEventOn('a'); - this.stub(Discourse.User, "currentProp").withArgs('external_links_in_new_tab').returns(true); + sandbox.stub(Discourse.User, "currentProp").withArgs('external_links_in_new_tab').returns(true); ok(!track(clickEvent)); - ok(this.windowOpen.calledWith('/clicks/track?url=http%3A%2F%2Fwww.google.com&post_id=42', '_blank')); + ok(windowOpen.calledWith('/clicks/track?url=http%3A%2F%2Fwww.google.com&post_id=42', '_blank')); }); test("tracks custom urls when opening in another window", function() { var clickEvent = generateClickEventOn('a'); ok(!track(clickEvent)); - ok(this.redirectTo.calledWith('/clicks/track?url=http%3A%2F%2Fwww.google.com&post_id=42')); + ok(redirectTo.calledWith('/clicks/track?url=http%3A%2F%2Fwww.google.com&post_id=42')); }); diff --git a/test/javascripts/lib/computed_test.js b/test/javascripts/lib/computed_test.js index db7c77d23..cf4862f09 100644 --- a/test/javascripts/lib/computed_test.js +++ b/test/javascripts/lib/computed_test.js @@ -1,6 +1,6 @@ module("Discourse.Computed", { setup: function() { - sinon.stub(I18n, "t", function(scope) { + sandbox.stub(I18n, "t", function(scope) { return "%@ translated: " + scope; }); }, diff --git a/test/javascripts/lib/html_test.js b/test/javascripts/lib/html_test.js index 1ee03a3d6..9e7da4099 100644 --- a/test/javascripts/lib/html_test.js +++ b/test/javascripts/lib/html_test.js @@ -35,7 +35,7 @@ test("undefined color", function() { test("allowUncategorized", function() { var uncategorized = Discourse.Category.create({name: 'uncategorized', id: 345}); - this.stub(Discourse.Site, 'currentProp').withArgs('uncategorized_category_id').returns(345); + sandbox.stub(Discourse.Site, 'currentProp').withArgs('uncategorized_category_id').returns(345); blank(html.categoryBadge(uncategorized), "it doesn't return HTML for uncategorized by default"); present(html.categoryBadge(uncategorized, {allowUncategorized: true}), "it returns HTML"); diff --git a/test/javascripts/lib/onebox_test.js b/test/javascripts/lib/onebox_test.js index e4ec15741..8bd0c8efe 100644 --- a/test/javascripts/lib/onebox_test.js +++ b/test/javascripts/lib/onebox_test.js @@ -5,7 +5,7 @@ module("Discourse.Onebox", { }); asyncTestDiscourse("Stops rapid calls with cache true", function() { - this.stub(Discourse, "ajax").returns(Ember.RSVP.resolve()); + sandbox.stub(Discourse, "ajax").returns(Ember.RSVP.resolve()); Discourse.Onebox.load(this.anchor, true); Discourse.Onebox.load(this.anchor, true); @@ -14,7 +14,7 @@ asyncTestDiscourse("Stops rapid calls with cache true", function() { }); asyncTestDiscourse("Stops rapid calls with cache true", function() { - this.stub(Discourse, "ajax").returns(Ember.RSVP.resolve()); + sandbox.stub(Discourse, "ajax").returns(Ember.RSVP.resolve()); Discourse.Onebox.load(this.anchor, false); Discourse.Onebox.load(this.anchor, false); diff --git a/test/javascripts/lib/url_test.js b/test/javascripts/lib/url_test.js index d3a6a2695..781712ca0 100644 --- a/test/javascripts/lib/url_test.js +++ b/test/javascripts/lib/url_test.js @@ -1,7 +1,7 @@ module("Discourse.URL"); test("isInternal with a HTTP url", function() { - this.stub(Discourse.URL, "origin").returns("http://eviltrout.com"); + sandbox.stub(Discourse.URL, "origin").returns("http://eviltrout.com"); not(Discourse.URL.isInternal(null), "a blank URL is not internal"); ok(Discourse.URL.isInternal("/test"), "relative URLs are internal"); @@ -11,7 +11,7 @@ test("isInternal with a HTTP url", function() { }); test("isInternal with a HTTPS url", function() { - this.stub(Discourse.URL, "origin").returns("https://eviltrout.com"); + sandbox.stub(Discourse.URL, "origin").returns("https://eviltrout.com"); ok(Discourse.URL.isInternal("http://eviltrout.com/monocle"), "HTTPS urls match HTTP urls"); }); @@ -20,7 +20,7 @@ test("isInternal with a HTTPS url", function() { // -------------------------------------------- // test("routeTo", function() { -// this.stub(Discourse.URL, "handleURL", function (path) { return path === "/t/topic-title/42"; }); +// sandbox.stub(Discourse.URL, "handleURL", function (path) { return path === "/t/topic-title/42"; }); // ok(Discourse.URL.routeTo("https://discourse.org/t/topic-title/42"), "can route HTTPS"); // ok(Discourse.URL.routeTo("http://discourse.org/t/topic-title/42"), "can route HTTP"); @@ -33,7 +33,7 @@ test("isInternal with a HTTPS url", function() { // test("navigatedToHome", function() { // var fakeDiscoveryController = { send: function() { return true; } }; // var mock = sinon.mock(fakeDiscoveryController); -// this.stub(Discourse.URL, "controllerFor").returns(fakeDiscoveryController); +// sandbox.stub(Discourse.URL, "controllerFor").returns(fakeDiscoveryController); // // mock.expects("send").withArgs('refresh').twice(); // ok(Discourse.URL.navigatedToHome("/", "/")); diff --git a/test/javascripts/lib/utilities_test.js b/test/javascripts/lib/utilities_test.js index 9fbe4d22c..6b611a93b 100644 --- a/test/javascripts/lib/utilities_test.js +++ b/test/javascripts/lib/utilities_test.js @@ -16,7 +16,7 @@ test("validateUploadedFiles", function() { }); test("uploading one file", function() { - this.stub(bootbox, "alert"); + sandbox.stub(bootbox, "alert"); not(validUpload([1, 2])); ok(bootbox.alert.calledWith(I18n.t('post.errors.too_many_uploads'))); @@ -24,7 +24,7 @@ test("uploading one file", function() { test("new user cannot upload images", function() { Discourse.SiteSettings.newuser_max_images = 0; - this.stub(bootbox, "alert"); + sandbox.stub(bootbox, "alert"); not(validUpload([{name: "image.png"}]), 'the upload is not valid'); ok(bootbox.alert.calledWith(I18n.t('post.errors.image_upload_not_allowed_for_new_user')), 'the alert is called'); @@ -32,7 +32,7 @@ test("new user cannot upload images", function() { test("new user cannot upload attachments", function() { Discourse.SiteSettings.newuser_max_attachments = 0; - this.stub(bootbox, "alert"); + sandbox.stub(bootbox, "alert"); not(validUpload([{name: "roman.txt"}])); ok(bootbox.alert.calledWith(I18n.t('post.errors.attachment_upload_not_allowed_for_new_user'))); @@ -41,7 +41,7 @@ test("new user cannot upload attachments", function() { test("ensures an authorized upload", function() { var html = { name: "unauthorized.html" }; var extensions = Discourse.SiteSettings.authorized_extensions.replace(/\|/g, ", "); - this.stub(bootbox, "alert"); + sandbox.stub(bootbox, "alert"); not(validUpload([html])); ok(bootbox.alert.calledWith(I18n.t('post.errors.upload_not_authorized', { authorized_extensions: extensions }))); @@ -51,7 +51,7 @@ test("prevents files that are too big from being uploaded", function() { var image = { name: "image.png", size: 10 * 1024 }; Discourse.SiteSettings.max_image_size_kb = 5; Discourse.User.currentProp("trust_level", 1); - this.stub(bootbox, "alert"); + sandbox.stub(bootbox, "alert"); not(validUpload([image])); ok(bootbox.alert.calledWith(I18n.t('post.errors.image_too_large', { max_size_kb: 5 }))); @@ -71,7 +71,7 @@ var dummyBlob = function() { test("allows valid uploads to go through", function() { Discourse.User.currentProp("trust_level", 1); Discourse.SiteSettings.max_image_size_kb = 15; - this.stub(bootbox, "alert"); + sandbox.stub(bootbox, "alert"); // image var image = { name: "image.png", size: 10 * 1024 }; diff --git a/test/javascripts/mixins/has_current_user_test.js b/test/javascripts/mixins/has_current_user_test.js index 81ab163ef..8f3057318 100644 --- a/test/javascripts/mixins/has_current_user_test.js +++ b/test/javascripts/mixins/has_current_user_test.js @@ -1,7 +1,7 @@ module("Discourse.HasCurrentUser"); test("adds `currentUser` property to an object and ensures it is not cached", function() { - this.stub(Discourse.User, "current"); + sandbox.stub(Discourse.User, "current"); var testObj = Ember.Object.createWithMixins(Discourse.HasCurrentUser, {}); Discourse.User.current.returns("first user"); diff --git a/test/javascripts/mixins/presence_test.js b/test/javascripts/mixins/presence_test.js index 6ae3c48da..268f42790 100644 --- a/test/javascripts/mixins/presence_test.js +++ b/test/javascripts/mixins/presence_test.js @@ -22,4 +22,4 @@ test("blank", function() { ok(testObj.blank('emptyArray'), "Empty arrays are blank"); ok(!testObj.blank('nonEmptyArray'), "Non empty arrays are not blank"); ok(testObj.blank('missing'), "Missing properties are blank"); -}); \ No newline at end of file +}); diff --git a/test/javascripts/mixins/singleton_test.js b/test/javascripts/mixins/singleton_test.js index 08f1b53d3..dba0f5ab7 100644 --- a/test/javascripts/mixins/singleton_test.js +++ b/test/javascripts/mixins/singleton_test.js @@ -58,4 +58,4 @@ test("createCurrent that returns null", function() { blank(Missing.current(), "it doesn't return an instance"); blank(Missing.currentProp('madeup'), "it won't raise an error asking for a property. Will just return null."); -}); \ No newline at end of file +}); diff --git a/test/javascripts/models/badge_test.js b/test/javascripts/models/badge_test.js index cd25d79c3..5087321ee 100644 --- a/test/javascripts/models/badge_test.js +++ b/test/javascripts/models/badge_test.js @@ -11,7 +11,7 @@ test('displayName', function() { var badge1 = Discourse.Badge.create({id: 1, name: "Test Badge 1"}); equal(badge1.get('displayName'), "Test Badge 1", "falls back to the original name in the absence of a translation"); - this.stub(I18n, "t").returnsArg(0); + sandbox.stub(I18n, "t").returnsArg(0); var badge2 = Discourse.Badge.create({id: 2, name: "Test Badge 2"}); equal(badge2.get('displayName'), "badges.badge.test_badge_2.name", "uses translation when available"); }); @@ -21,7 +21,7 @@ test('translatedDescription', function() { equal(badge1.get('translatedDescription'), null, "returns null when no translation exists"); var badge2 = Discourse.Badge.create({id: 2, name: "Test Badge 2 **"}); - this.stub(I18n, "t").returns("description translation"); + sandbox.stub(I18n, "t").returns("description translation"); equal(badge2.get('translatedDescription'), "description translation", "users translated description"); }); @@ -30,7 +30,7 @@ test('displayDescription', function() { equal(badge1.get('displayDescription'), "TEST", "returns original description when no translation exists"); var badge2 = Discourse.Badge.create({id: 2, name: "Test Badge 2 **"}); - this.stub(I18n, "t").returns("description translation"); + sandbox.stub(I18n, "t").returns("description translation"); equal(badge2.get('displayDescription'), "description translation", "users translated description"); }); @@ -61,7 +61,7 @@ test('updateFromJson', function() { }); test('save', function() { - this.stub(Discourse, 'ajax').returns(Ember.RSVP.resolve({})); + sandbox.stub(Discourse, 'ajax').returns(Ember.RSVP.resolve({})); var badge = Discourse.Badge.create({name: "New Badge", description: "This is a new badge.", badge_type_id: 1}); // TODO: clean API badge.save(["name", "description", "badge_type_id"]); @@ -69,7 +69,7 @@ test('save', function() { }); test('destroy', function() { - this.stub(Discourse, 'ajax'); + sandbox.stub(Discourse, 'ajax'); var badge = Discourse.Badge.create({name: "New Badge", description: "This is a new badge.", badge_type_id: 1}); badge.destroy(); ok(!Discourse.ajax.calledOnce, "no AJAX call for a new badge"); diff --git a/test/javascripts/models/category_test.js b/test/javascripts/models/category_test.js index 6d9f7c0ed..5334b67dd 100644 --- a/test/javascripts/models/category_test.js +++ b/test/javascripts/models/category_test.js @@ -31,7 +31,7 @@ test('findBySlug', function() { luke = Discourse.Category.create({id: 2, slug: 'luke', parentCategory: darth}), categoryList = [darth, luke]; - this.stub(Discourse.Category, 'list').returns(categoryList); + sandbox.stub(Discourse.Category, 'list').returns(categoryList); equal(Discourse.Category.findBySlug('darth'), darth, 'we can find a parent category'); equal(Discourse.Category.findBySlug('luke', 'darth'), luke, 'we can find a child with parent'); @@ -45,7 +45,7 @@ test('findByIds', function() { 2: Discourse.Category.create({id: 2}) }; - this.stub(Discourse.Category, 'idMap').returns(categories); + sandbox.stub(Discourse.Category, 'idMap').returns(categories); deepEqual(Discourse.Category.findByIds([1,2,3]), _.values(categories)); }); diff --git a/test/javascripts/models/composer_test.js b/test/javascripts/models/composer_test.js index f9bb57bae..7d271ef1b 100644 --- a/test/javascripts/models/composer_test.js +++ b/test/javascripts/models/composer_test.js @@ -1,6 +1,6 @@ module("Discourse.Composer", { setup: function() { - sinon.stub(Discourse.User, 'currentProp').withArgs('admin').returns(false); + sandbox.stub(Discourse.User, 'currentProp').withArgs('admin').returns(false); }, teardown: function() { @@ -130,7 +130,7 @@ test("Title length for private messages", function() { }); test('importQuote with no data', function() { - this.stub(Discourse.Post, 'load'); + sandbox.stub(Discourse.Post, 'load'); var composer = Discourse.Composer.create(); composer.importQuote(); blank(composer.get('reply'), 'importing with no topic adds nothing'); @@ -158,7 +158,7 @@ test('editingFirstPost', function() { asyncTestDiscourse('importQuote with a post', function() { expect(1); - this.stub(Discourse.Post, 'load').withArgs(123).returns(Em.Deferred.promise(function (p) { + sandbox.stub(Discourse.Post, 'load').withArgs(123).returns(Em.Deferred.promise(function (p) { p.resolve(Discourse.Post.create({raw: "let's quote"})); })); @@ -172,7 +172,7 @@ asyncTestDiscourse('importQuote with a post', function() { asyncTestDiscourse('importQuote with no post', function() { expect(1); - this.stub(Discourse.Post, 'load').withArgs(4).returns(Em.Deferred.promise(function (p) { + sandbox.stub(Discourse.Post, 'load').withArgs(4).returns(Em.Deferred.promise(function (p) { p.resolve(Discourse.Post.create({raw: 'quote me'})); })); @@ -243,7 +243,7 @@ test('open with a quote', function() { module("Discourse.Composer as admin", { setup: function() { - sinon.stub(Discourse.User, 'currentProp').withArgs('admin').returns(true); + sandbox.stub(Discourse.User, 'currentProp').withArgs('admin').returns(true); }, teardown: function() { @@ -267,4 +267,4 @@ test("Title length for regular topics as admin", function() { composer.set('title', ''); ok(!composer.get('titleLengthValid'), "admins must set title to at least 1 character"); -}); \ No newline at end of file +}); diff --git a/test/javascripts/models/email_log_test.js b/test/javascripts/models/email_log_test.js index e86a0980c..bce4017fb 100644 --- a/test/javascripts/models/email_log_test.js +++ b/test/javascripts/models/email_log_test.js @@ -2,4 +2,4 @@ module("Discourse.EmailLog"); test("create", function() { ok(Discourse.EmailLog.create(), "it can be created without arguments"); -}); \ No newline at end of file +}); diff --git a/test/javascripts/models/invite_test.js b/test/javascripts/models/invite_test.js index 0989d0c38..0bdc51a01 100644 --- a/test/javascripts/models/invite_test.js +++ b/test/javascripts/models/invite_test.js @@ -2,4 +2,4 @@ module("Discourse.Invite"); test("create", function() { ok(Discourse.Invite.create(), "it can be created without arguments"); -}); \ No newline at end of file +}); diff --git a/test/javascripts/models/post_stream_test.js b/test/javascripts/models/post_stream_test.js index dbb069cdf..3e65a9484 100644 --- a/test/javascripts/models/post_stream_test.js +++ b/test/javascripts/models/post_stream_test.js @@ -111,7 +111,7 @@ test("removePosts", function() { test("cancelFilter", function() { var postStream = buildStream(1235); - this.stub(postStream, "refresh"); + sandbox.stub(postStream, "refresh"); postStream.set('summary', true); postStream.cancelFilter(); @@ -124,7 +124,7 @@ test("cancelFilter", function() { test("toggleParticipant", function() { var postStream = buildStream(1236); - this.stub(postStream, "refresh"); + sandbox.stub(postStream, "refresh"); equal(postStream.get('userFilters.length'), 0, "by default no participants are toggled"); @@ -137,7 +137,7 @@ test("toggleParticipant", function() { test("streamFilters", function() { var postStream = buildStream(1237); - this.stub(postStream, "refresh"); + sandbox.stub(postStream, "refresh"); deepEqual(postStream.get('streamFilters'), {}, "there are no postFilters by default"); ok(postStream.get('hasNoFilters'), "there are no filters by default"); @@ -254,7 +254,7 @@ asyncTestDiscourse("loadIntoIdentityMap with no data", function() { var postStream = buildStream(1234); expect(1); - this.stub(Discourse, "ajax"); + sandbox.stub(Discourse, "ajax"); postStream.loadIntoIdentityMap([]).then(function() { ok(!Discourse.ajax.calledOnce, "an empty array returned a promise yet performed no ajax request"); start(); @@ -265,7 +265,7 @@ asyncTestDiscourse("loadIntoIdentityMap with post ids", function() { var postStream = buildStream(1234); expect(1); - this.stub(Discourse, "ajax").returns(Ember.RSVP.resolve({ + sandbox.stub(Discourse, "ajax").returns(Ember.RSVP.resolve({ post_stream: { posts: [{id: 10, post_number: 10}] } @@ -285,7 +285,7 @@ asyncTestDiscourse("loading a post's history", function() { var secondPost = Discourse.Post.create({id: 2222}); - this.stub(Discourse, "ajax").returns(Ember.RSVP.resolve([secondPost])); + sandbox.stub(Discourse, "ajax").returns(Ember.RSVP.resolve([secondPost])); postStream.findReplyHistory(post).then(function() { ok(Discourse.ajax.calledOnce, "it made the ajax request"); present(postStream.findLoadedPost(2222), "it stores the returned post in the identity map"); @@ -367,8 +367,8 @@ test("staging and committing a post", function() { test('triggerNewPostInStream', function() { var postStream = buildStream(225566); - this.stub(postStream, 'appendMore'); - this.stub(postStream, 'refresh'); + sandbox.stub(postStream, 'appendMore'); + sandbox.stub(postStream, 'refresh'); postStream.triggerNewPostInStream(null); ok(!postStream.appendMore.calledOnce, "asking for a null id does nothing"); @@ -418,7 +418,7 @@ test("comitting and triggerNewPostInStream race condition", function() { equal(postStream.get('filteredPostsCount'), 0, "it has no filteredPostsCount yet"); stagedPost.set('id', 123); - this.stub(postStream, 'appendMore'); + sandbox.stub(postStream, 'appendMore'); postStream.triggerNewPostInStream(123); equal(postStream.get('filteredPostsCount'), 1, "it added the post"); diff --git a/test/javascripts/models/post_test.js b/test/javascripts/models/post_test.js index cac49f5bb..45e4d8434 100644 --- a/test/javascripts/models/post_test.js +++ b/test/javascripts/models/post_test.js @@ -59,7 +59,7 @@ test('destroy by staff', function() { var user = Discourse.User.create({username: 'staff', staff: true}); var post = buildPost({user: user}); - this.stub(Discourse, 'ajax').returns(new Em.Deferred()); + sandbox.stub(Discourse, 'ajax').returns(new Em.Deferred()); post.destroy(user); present(post.get('deleted_at'), "it has a `deleted_at` field."); @@ -77,7 +77,7 @@ test('destroy by non-staff', function() { var user = Discourse.User.create({username: 'evil trout'}); var post = buildPost({user: user, cooked: originalCooked}); - this.stub(Discourse, 'ajax'); + sandbox.stub(Discourse, 'ajax'); post.destroy(user); ok(!post.get('can_delete'), "the post can't be deleted again in this session"); diff --git a/test/javascripts/models/session_test.js b/test/javascripts/models/session_test.js index ce33a5842..84589a9c7 100644 --- a/test/javascripts/models/session_test.js +++ b/test/javascripts/models/session_test.js @@ -3,4 +3,4 @@ module("Discourse.Session"); test('highestSeenByTopic', function() { var session = Discourse.Session.current(); deepEqual(session.get('highestSeenByTopic'), {}, "by default it returns an empty object"); -}); \ No newline at end of file +}); diff --git a/test/javascripts/models/site_test.js b/test/javascripts/models/site_test.js index e5e53935d..9dcc8ff1b 100644 --- a/test/javascripts/models/site_test.js +++ b/test/javascripts/models/site_test.js @@ -36,4 +36,4 @@ test('create categories', function() { present(subcategory, "it loaded the subcategory"); equal(subcategory.get('parentCategory'), parent, "it has associated the child with the parent"); -}); \ No newline at end of file +}); diff --git a/test/javascripts/models/staff_action_log_test.js b/test/javascripts/models/staff_action_log_test.js index ba7447480..9dbac57d0 100644 --- a/test/javascripts/models/staff_action_log_test.js +++ b/test/javascripts/models/staff_action_log_test.js @@ -2,4 +2,4 @@ module("Discourse.StaffActionLog"); test("create", function() { ok(Discourse.StaffActionLog.create(), "it can be created without arguments"); -}); \ No newline at end of file +}); diff --git a/test/javascripts/models/topic_test.js b/test/javascripts/models/topic_test.js index 4fb86c1f3..1ab2d2596 100644 --- a/test/javascripts/models/topic_test.js +++ b/test/javascripts/models/topic_test.js @@ -48,7 +48,7 @@ test("destroy", function() { var user = Discourse.User.create({username: 'eviltrout'}); var topic = Discourse.Topic.create({id: 1234}); - this.stub(Discourse, 'ajax'); + sandbox.stub(Discourse, 'ajax'); topic.destroy(user); present(topic.get('deleted_at'), 'deleted at is set'); @@ -60,10 +60,10 @@ test("recover", function() { var user = Discourse.User.create({username: 'eviltrout'}); var topic = Discourse.Topic.create({id: 1234, deleted_at: new Date(), deleted_by: user}); - this.stub(Discourse, 'ajax'); + sandbox.stub(Discourse, 'ajax'); topic.recover(); blank(topic.get('deleted_at'), "it clears deleted_at"); blank(topic.get('deleted_by'), "it clears deleted_by"); //ok(Discourse.ajax.calledOnce, "it called recover over the wire"); -}); \ No newline at end of file +}); diff --git a/test/javascripts/models/user_badge_test.js b/test/javascripts/models/user_badge_test.js index c4e896d8c..70942b395 100644 --- a/test/javascripts/models/user_badge_test.js +++ b/test/javascripts/models/user_badge_test.js @@ -19,7 +19,7 @@ test('createFromJson array', function() { asyncTestDiscourse('findByUsername', function() { expect(2); - this.stub(Discourse, 'ajax').returns(Ember.RSVP.resolve(multipleBadgesJson)); + sandbox.stub(Discourse, 'ajax').returns(Ember.RSVP.resolve(multipleBadgesJson)); Discourse.UserBadge.findByUsername("anne3").then(function(badges) { ok(Array.isArray(badges), "returns an array"); start(); @@ -29,7 +29,7 @@ asyncTestDiscourse('findByUsername', function() { asyncTestDiscourse('findByBadgeId', function() { expect(2); - this.stub(Discourse, 'ajax').returns(Ember.RSVP.resolve(multipleBadgesJson)); + sandbox.stub(Discourse, 'ajax').returns(Ember.RSVP.resolve(multipleBadgesJson)); Discourse.UserBadge.findByBadgeId(880).then(function(badges) { ok(Array.isArray(badges), "returns an array"); start(); @@ -39,7 +39,7 @@ asyncTestDiscourse('findByBadgeId', function() { asyncTestDiscourse('grant', function() { expect(2); - this.stub(Discourse, 'ajax').returns(Ember.RSVP.resolve(singleBadgeJson)); + sandbox.stub(Discourse, 'ajax').returns(Ember.RSVP.resolve(singleBadgeJson)); Discourse.UserBadge.grant(1, "username").then(function(userBadge) { ok(!Array.isArray(userBadge), "does not return an array"); start(); @@ -48,7 +48,7 @@ asyncTestDiscourse('grant', function() { }); test('revoke', function() { - this.stub(Discourse, 'ajax'); + sandbox.stub(Discourse, 'ajax'); var userBadge = Discourse.UserBadge.create({id: 1}); userBadge.revoke(); ok(Discourse.ajax.calledOnce, "makes an AJAX call"); diff --git a/test/javascripts/templates/site_map_test.js b/test/javascripts/templates/site_map_test.js index a4025ec39..c9bd0fcca 100644 --- a/test/javascripts/templates/site_map_test.js +++ b/test/javascripts/templates/site_map_test.js @@ -22,7 +22,7 @@ var categoryLinksSelector = ".category-links"; module("Template: site_map", { setup: function() { - sinon.stub(I18n, "t", function(scope, options) { + sandbox.stub(I18n, "t", function(scope, options) { if (options) { if (options.count) { return [scope, options.count].join(" "); @@ -39,6 +39,7 @@ module("Template: site_map", { }, teardown: function() { + Discourse.reset(); I18n.t.restore(); } }); @@ -91,7 +92,7 @@ test("location links part is rendered correctly", function() { }); test("binds mobile theme toggle link to the correct controller action", function() { - this.stub(Ember.Handlebars.helpers, "action", function(actionName) { + sandbox.stub(Ember.Handlebars.helpers, "action", function(actionName) { return new Handlebars.SafeString('data-test-stub-action-name="' + actionName + '"'); }); diff --git a/test/javascripts/test_helper.js b/test/javascripts/test_helper.js index adc8ca682..a0028c82b 100644 --- a/test/javascripts/test_helper.js +++ b/test/javascripts/test_helper.js @@ -92,16 +92,25 @@ if (window.Logster) { window.Logster = { enabled: false }; } -QUnit.testStart(function() { +var origDebounce = Ember.run.debounce; +QUnit.testStart(function(ctx) { // Allow our tests to change site settings and have them reset before the next test Discourse.SiteSettings = jQuery.extend(true, {}, Discourse.SiteSettingsOriginal); Discourse.BaseUri = "/"; Discourse.BaseUrl = ""; - // Never debounce in test, just makes testing harder - sinon.stub(Ember.run, "debounce").callsArg(1) + window.sandbox = sinon.sandbox.create(); + + window.sandbox.stub(Discourse.ScrollingDOMMethods, "bindOnScroll"); + window.sandbox.stub(Discourse.ScrollingDOMMethods, "unbindOnScroll"); + + // Don't debounce in test unless we're testing debouncing + if (ctx.module.indexOf('debounce') === -1) { + Ember.run.debounce = Ember.run; + } }); QUnit.testDone(function() { - Ember.run.debounce.restore(); + Ember.run.debounce = origDebounce; + window.sandbox.restore(); }); diff --git a/test/javascripts/views/container_view_test.js b/test/javascripts/views/container_view_test.js index 6a8093bc0..c46255943 100644 --- a/test/javascripts/views/container_view_test.js +++ b/test/javascripts/views/container_view_test.js @@ -1,85 +1,88 @@ -var SomeViewClass = Ember.View.extend(), - containerView; +var SomeViewClass = Ember.View.extend(); -function containerHasOnlyOneChild(klass) { +function containerHasOnlyOneChild(containerView, klass) { equal(containerView.get('childViews').length, 1, "container has no other children than the one created by method"); ok(containerView.objectAt(0) instanceof klass, "container's child created by method is an instance of a correct class"); } -function containerHasTwoChildren(klass1, klass2) { +function containerHasTwoChildren(containerView, klass1, klass2) { equal(containerView.get('childViews').length, 2, "container has both already existing and newly created children"); ok(containerView.objectAt(0) instanceof klass1, "already existing child's class is correct"); ok(containerView.objectAt(1) instanceof klass2, "newly created child's class is correct"); } -var childHasProperty = function(name) { +function childHasProperty(containerView, name) { equal(containerView.objectAt(0).get(name), name, "method passes properties to the container's child it creates"); -}; +} -module("view:container", { - setup: function() { - containerView = Discourse.__container__.lookup('view:container'); - } -}); +moduleFor("view:container"); test("mixes in Discourse.Presence", function() { + var containerView = this.subject(); ok(Discourse.Presence.detect(containerView)); }); test("attachViewWithArgs: creates a view of a given class with given properties and appends it to the container", function() { + var containerView = this.subject(); containerView.attachViewWithArgs({foo: "foo"}, SomeViewClass); - - containerHasOnlyOneChild(SomeViewClass); - childHasProperty("foo"); + containerHasOnlyOneChild(containerView, SomeViewClass); + childHasProperty(containerView, "foo"); }); test("attachViewWithArgs: creates a view of a given class without any properties and appends it to the container", function() { - containerView.attachViewWithArgs(null, SomeViewClass); - containerHasOnlyOneChild(SomeViewClass); + var containerView = this.subject(); + containerView.attachViewWithArgs(null, SomeViewClass); + containerHasOnlyOneChild(containerView, SomeViewClass); }); test("attachViewWithArgs: creates a view without class specified (Ember.View is used by default) with given properties and appends it to the container", function() { + var containerView = this.subject(); containerView.attachViewWithArgs({foo: "foo"}); - containerHasOnlyOneChild(Ember.View); - childHasProperty("foo"); + containerHasOnlyOneChild(containerView, Ember.View); + childHasProperty(containerView, "foo"); }); test("attachViewWithArgs: creates a view without class specified (Ember.View is used by default) without any properties and appends it to the container", function() { + var containerView = this.subject(); containerView.attachViewWithArgs(); - containerHasOnlyOneChild(Ember.View); + containerHasOnlyOneChild(containerView, Ember.View); }); test("attachViewWithArgs: appends a view to a container already containing other views", function() { var AlreadyContainedViewClass = Ember.View.extend(); var alreadyContainedView = AlreadyContainedViewClass.create(); + var containerView = this.subject(); containerView.pushObject(alreadyContainedView); containerView.attachViewWithArgs(null, SomeViewClass); - containerHasTwoChildren(AlreadyContainedViewClass, SomeViewClass); + containerHasTwoChildren(containerView, AlreadyContainedViewClass, SomeViewClass); }); test("attachViewClass: creates a view of a given class without any properties and appends it to the container", function() { + var containerView = this.subject(); containerView.attachViewClass(SomeViewClass); - containerHasOnlyOneChild(SomeViewClass); + containerHasOnlyOneChild(containerView, SomeViewClass); }); test("attachViewClass: creates a view without class specified (Ember.View is used by default) without any properties and appends it to the container", function() { + var containerView = this.subject(); containerView.attachViewClass(); - containerHasOnlyOneChild(Ember.View); + containerHasOnlyOneChild(containerView, Ember.View); }); test("attachViewClass: appends a view to a container already containing other views", function() { var AlreadyContainedViewClass = Ember.View.extend(); var alreadyContainedView = AlreadyContainedViewClass.create(); + var containerView = this.subject(); containerView.pushObject(alreadyContainedView); containerView.attachViewClass(SomeViewClass); - containerHasTwoChildren(AlreadyContainedViewClass, SomeViewClass); + containerHasTwoChildren(containerView, AlreadyContainedViewClass, SomeViewClass); }); diff --git a/test/javascripts/views/header_view_test.js b/test/javascripts/views/header_view_test.js index 6491306c4..2ba9595bb 100644 --- a/test/javascripts/views/header_view_test.js +++ b/test/javascripts/views/header_view_test.js @@ -1,13 +1,10 @@ -module("Discourse.HeaderView"); +moduleFor("view:header"); test("showNotifications", function() { var controllerSpy = { send: sinon.spy() }; - var view = viewClassFor('header').create({ - controller: controllerSpy - }); - + var view = this.subject({controller: controllerSpy}); view.showNotifications(); ok(controllerSpy.send.calledWith("showNotifications", view), "sends showNotifications message to the controller, passing header view as a param"); diff --git a/test/javascripts/views/text_field_test.js b/test/javascripts/views/text_field_test.js index f1047b369..7f285703b 100644 --- a/test/javascripts/views/text_field_test.js +++ b/test/javascripts/views/text_field_test.js @@ -1,59 +1,17 @@ -var appendTextFieldWithProperties = function(properties) { - var view = componentClassFor('text-field').create(properties); - Ember.run(function() { - view.appendTo(fixture()); - }); -}; - -var hasAttr = function($element, attrName, attrValue) { - equal($element.attr(attrName), attrValue, "'" + attrName + "' attribute is correctly rendered"); -}; - -var hasNoAttr = function($element, attrName) { - equal($element.attr(attrName), undefined, "'" + attrName + "' attribute is not rendered"); -}; - -module("view:text-field"); +moduleForComponent("text-field"); test("renders correctly with no properties set", function() { - appendTextFieldWithProperties({}); - - var $input = fixture("input"); - hasAttr($input, "type", "text"); - hasAttr($input, "placeholder", ""); - hasNoAttr($input, "autocorrect"); - hasNoAttr($input, "autocapitalize"); - hasNoAttr($input, "autofocus"); + var component = this.subject(); + equal(component.get('type'), "text"); }); -test("renders correctly with all allowed properties set", function() { - this.stub(I18n, "t").returnsArg(0); +test("support a placeholder", function() { + sandbox.stub(I18n, "t").returnsArg(0); - appendTextFieldWithProperties({ - autocorrect: "on", - autocapitalize: "off", - autofocus: "autofocus", + var component = this.subject({ placeholderKey: "placeholder.i18n.key" }); - var $input = fixture("input"); - hasAttr($input, "type", "text"); - hasAttr($input, "placeholder", "placeholder.i18n.key"); - hasAttr($input, "autocorrect", "on"); - hasAttr($input, "autocapitalize", "off"); - hasAttr($input, "autofocus", "autofocus"); + equal(component.get('type'), "text"); + equal(component.get('placeholder'), "placeholder.i18n.key"); }); - -// NEIL commented out this test. It fails now that TextField is in the components dir. - -// test("is registered as helper", function() { -// var view = Ember.View.create({ -// template: Ember.Handlebars.compile("{{text-field}}") -// }); - -// Ember.run(function() { -// view.appendTo(fixture()); -// }); - -// ok(exists(fixture("input"))); -// });