From 451a818162325908a5b187e40f69ce795471d5d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Hanol?= Date: Mon, 22 Apr 2013 20:21:29 +0200 Subject: [PATCH] do not display clicks count in oneboxes --- .../discourse/components/click_track.js | 9 +- .../javascripts/discourse/components/url.js | 26 ++- .../preferences_username_controller.js | 8 +- .../views/modal/edit_category_view.js | 5 +- .../javascripts/discourse/views/post_view.js | 5 +- .../components/click_track_spec.js | 215 ++++++++++++++++++ 6 files changed, 257 insertions(+), 11 deletions(-) create mode 100644 spec/javascripts/components/click_track_spec.js diff --git a/app/assets/javascripts/discourse/components/click_track.js b/app/assets/javascripts/discourse/components/click_track.js index 5f79398041e..41cad2cb0ed 100644 --- a/app/assets/javascripts/discourse/components/click_track.js +++ b/app/assets/javascripts/discourse/components/click_track.js @@ -53,7 +53,10 @@ Discourse.ClickTrack = { if (!ownLink) { var $badge = $('span.badge', $link); if ($badge.length === 1) { - $badge.html(parseInt($badge.html(), 10) + 1); + // don't update counts in oneboxes (except when we force it) + if ($link.closest(".onebox-result").length === 0 || $link.hasClass("track-link")) { + $badge.html(parseInt($badge.html(), 10) + 1); + } } } @@ -79,7 +82,7 @@ Discourse.ClickTrack = { } // If we're on the same site, use the router and track via AJAX - if (href.indexOf(window.location.origin) === 0) { + if (href.indexOf(Discourse.URL.origin()) === 0) { Discourse.ajax(Discourse.getURL("/clicks/track"), { data: { url: href, @@ -97,7 +100,7 @@ Discourse.ClickTrack = { var win = window.open(trackingUrl, '_blank'); win.focus(); } else { - window.location = trackingUrl; + Discourse.URL.redirectTo(trackingUrl); } return false; diff --git a/app/assets/javascripts/discourse/components/url.js b/app/assets/javascripts/discourse/components/url.js index 4191b874006..917a929c9be 100644 --- a/app/assets/javascripts/discourse/components/url.js +++ b/app/assets/javascripts/discourse/components/url.js @@ -21,7 +21,7 @@ Discourse.URL = { @method router **/ - router: function(path) { + router: function() { return Discourse.__container__.lookup('router:main'); }, @@ -105,6 +105,30 @@ Discourse.URL = { var router = this.router(); router.router.updateURL(path); return router.handleURL(path); + }, + + /** + @private + + Get the origin of the current location. + This has been extracted so it can be tested. + + @method origin + **/ + origin: function() { + return window.location.origin; + }, + + /** + @private + + Redirect to a URL. + This has been extracted so it can be tested. + + @method redirectTo + **/ + redirectTo: function(url) { + window.location = url; } }; diff --git a/app/assets/javascripts/discourse/controllers/preferences_username_controller.js b/app/assets/javascripts/discourse/controllers/preferences_username_controller.js index 0ec57d910a1..d67319581b7 100644 --- a/app/assets/javascripts/discourse/controllers/preferences_username_controller.js +++ b/app/assets/javascripts/discourse/controllers/preferences_username_controller.js @@ -55,12 +55,12 @@ Discourse.PreferencesUsernameController = Discourse.ObjectController.extend({ if (result) { _this.set('saving', true); return _this.get('content').changeUsername(_this.get('newUsername')).then(function() { - window.location = Discourse.getURL("/users/") + (_this.get('newUsername').toLowerCase()) + "/preferences"; + var url = Discourse.getURL("/users/") + _this.get('newUsername').toLowerCase() + "/preferences"; + Discourse.URL.redirectTo(url); }, function() { - /* Error - */ + // error _this.set('error', true); - return _this.set('saving', false); + _this.set('saving', false); }); } }); diff --git a/app/assets/javascripts/discourse/views/modal/edit_category_view.js b/app/assets/javascripts/discourse/views/modal/edit_category_view.js index 279e09297be..57cd0bafc30 100644 --- a/app/assets/javascripts/discourse/views/modal/edit_category_view.js +++ b/app/assets/javascripts/discourse/views/modal/edit_category_view.js @@ -95,7 +95,8 @@ Discourse.EditCategoryView = Discourse.ModalBodyView.extend({ this.get('category').save().then(function(result) { // success $('#discourse-modal').modal('hide'); - window.location = Discourse.getURL("/category/") + (Discourse.Utilities.categoryUrlId(result.category)); + var url = Discourse.getURL("/category/") + (Discourse.Utilities.categoryUrlId(result.category)); + Discourse.URL.redirectTo(url); }, function(errors) { // errors if(errors.length === 0) errors.push(Em.String.i18n("category.creation_error")); @@ -112,7 +113,7 @@ Discourse.EditCategoryView = Discourse.ModalBodyView.extend({ if (result) { categoryView.get('category').destroy().then(function(){ // success - window.location = Discourse.getURL("/categories"); + Discourse.URL.redirectTo(Discourse.getURL("/categories")); }, function(jqXHR){ // error $('#discourse-modal').modal('show'); diff --git a/app/assets/javascripts/discourse/views/post_view.js b/app/assets/javascripts/discourse/views/post_view.js index f274c8784b5..ab298a45e56 100644 --- a/app/assets/javascripts/discourse/views/post_view.js +++ b/app/assets/javascripts/discourse/views/post_view.js @@ -186,7 +186,10 @@ Discourse.PostView = Discourse.View.extend({ postView.$(".cooked a[href]").each(function() { var link = $(this); if (link.attr('href') === lc.url) { - return link.append("" + lc.clicks + ""); + // don't display badge counts in oneboxes (except when we force it) + if (link.closest(".onebox-result").length === 0 || link.hasClass("track-link")) { + link.append("" + lc.clicks + ""); + } } }); } diff --git a/spec/javascripts/components/click_track_spec.js b/spec/javascripts/components/click_track_spec.js new file mode 100644 index 00000000000..0a37080dab7 --- /dev/null +++ b/spec/javascripts/components/click_track_spec.js @@ -0,0 +1,215 @@ +/*global expect:true describe:true it:true beforeEach:true afterEach:true spyOn:true */ + +describe("Discourse.ClickTrack", function() { + + var track = Discourse.ClickTrack.trackClick, + clickEvent, + html = [ + '
', + ' ', + '
'].join("\n"); + + var generateClickEventOn = function(selector) { + return $.Event("click", { currentTarget: $(selector)[0] }); + } + + beforeEach(function() { + $('body').html(html); + }); + + afterEach(function() { + $('#topic').remove(); + }); + + describe("lightboxes", function() { + + beforeEach(function() { + clickEvent = generateClickEventOn('.lightbox'); + }); + + it("does not track clicks on lightboxes", function() { + expect(track(clickEvent)).toBe(true); + }); + + it("does not call preventDefault", function() { + spyOn(clickEvent, "preventDefault"); + track(clickEvent); + expect(clickEvent.preventDefault).not.toHaveBeenCalled(); + }); + + }); + + it("calls preventDefault", function() { + clickEvent = generateClickEventOn('a'); + spyOn(clickEvent, "preventDefault"); + track(clickEvent); + expect(clickEvent.preventDefault).toHaveBeenCalled(); + }); + + it("does not track clicks on back buttons", function() { + clickEvent = generateClickEventOn('.back'); + expect(track(clickEvent)).toBe(true); + }); + + it("does not track clicks on quote buttons", function() { + clickEvent = generateClickEventOn('.quote-other-topic'); + expect(track(clickEvent)).toBe(true); + }); + + it("removes the href and put it as a data attribute", function() { + clickEvent = generateClickEventOn('a'); + track(clickEvent); + var $link = $('a').first(); + expect($link.hasClass('no-href')).toBe(true); + expect($link.data('href')).toEqual("http://www.google.com"); + expect($link.attr('href')).toBeUndefined(); + expect($link.data('auto-route')).toBe(true); + }); + + describe("badges", function() { + + it("does not update badge clicks on my own link", function() { + spyOn(Discourse, "get").andReturn(314); + track(generateClickEventOn('#with-badge')); + var $badge = $('span.badge', $('#with-badge').first()); + expect(parseInt($badge.html(), 10)).toEqual(1); + }); + + it("does not update badge clicks on links in my own post", function() { + spyOn(Discourse, "get").andReturn(3141); + track(generateClickEventOn('#with-badge-but-not-mine')); + var $badge = $('span.badge', $('#with-badge-but-not-mine').first()); + expect(parseInt($badge.html(), 10)).toEqual(1); + }); + + describe("oneboxes", function() { + + it("does not update badge clicks in oneboxes", function() { + track(generateClickEventOn('#inside-onebox')); + var $badge = $('span.badge', $('#inside-onebox').first()); + expect(parseInt($badge.html(), 10)).toEqual(1); + }); + + it("updates badge clicks in oneboxes when forced", function() { + track(generateClickEventOn('#inside-onebox-forced')); + var $badge = $('span.badge', $('#inside-onebox-forced').first()); + expect(parseInt($badge.html(), 10)).toEqual(2); + }); + + }); + + it("updates badge clicks", function() { + track(generateClickEventOn('#with-badge')); + var $badge = $('span.badge', $('#with-badge').first()); + expect(parseInt($badge.html(), 10)).toEqual(2); + }); + + }); + + describe("right click", function() { + + beforeEach(function(){ + clickEvent = generateClickEventOn('a'); + clickEvent.which = 3; + }); + + it("detects right clicks", function() { + expect(track(clickEvent)).toBe(true); + }); + + it("changes the href", function() { + track(clickEvent); + var $link = $('a').first(); + expect($link.attr('href')).toEqual("http://www.google.com"); + }); + + it("tracks external right clicks", function() { + Discourse.SiteSettings.track_external_right_clicks = true; + track(clickEvent); + var $link = $('a').first(); + expect($link.attr('href')).toEqual("/clicks/track?url=http%3A%2F%2Fwww.google.com&post_id=42"); + // reset + Discourse.SiteSettings.track_external_right_clicks = false; + }); + + }); + + describe("new tab", function() { + + beforeEach(function(){ + clickEvent = generateClickEventOn('a'); + spyOn(Discourse, 'ajax'); + spyOn(window, 'open'); + }); + + it("opens in a new tab when pressing alt", function() { + clickEvent.metaKey = true; + expect(track(clickEvent)).toBe(false); + expect(Discourse.ajax).toHaveBeenCalled(); + expect(window.open).toHaveBeenCalledWith('http://www.google.com', '_blank'); + }); + + it("opens in a new tab when pressing ctrl", function() { + clickEvent.ctrlKey = true; + expect(track(clickEvent)).toBe(false); + expect(Discourse.ajax).toHaveBeenCalled(); + expect(window.open).toHaveBeenCalledWith('http://www.google.com', '_blank'); + }); + + it("opens in a new tab when middle clicking", function() { + clickEvent.which = 2; + expect(track(clickEvent)).toBe(false); + expect(Discourse.ajax).toHaveBeenCalled(); + expect(window.open).toHaveBeenCalledWith('http://www.google.com', '_blank'); + }); + + }); + + it("tracks via AJAX if we're on the same site", function() { + // setup + clickEvent = generateClickEventOn('#same-site'); + spyOn(Discourse, 'ajax'); + spyOn(Discourse.URL, 'routeTo'); + spyOn(Discourse.URL, 'origin').andReturn('http://discuss.domain.com'); + // test + expect(track(clickEvent)).toBe(false); + expect(Discourse.ajax).toHaveBeenCalled(); + expect(Discourse.URL.routeTo).toHaveBeenCalledWith('http://discuss.domain.com'); + }); + + describe("tracks via custom URL", function() { + + beforeEach(function() { + clickEvent = generateClickEventOn('a'); + }); + + it("in another window", function() { + // spies + spyOn(Discourse, 'get').andReturn(true); + spyOn(window, 'open').andCallFake(function() { return { focus: function() {} } }); + spyOn(window, 'focus'); + // test + expect(track(clickEvent)).toBe(false); + expect(Discourse.get).toHaveBeenCalledWith('currentUser.external_links_in_new_tab'); + expect(window.open).toHaveBeenCalledWith('/clicks/track?url=http%3A%2F%2Fwww.google.com&post_id=42', '_blank'); + }); + + it("in the same window", function() { + spyOn(Discourse.URL, 'redirectTo'); + expect(track(clickEvent)).toBe(false); + expect(Discourse.URL.redirectTo).toHaveBeenCalledWith('/clicks/track?url=http%3A%2F%2Fwww.google.com&post_id=42'); + }); + + }); + +});