diff --git a/app/assets/javascripts/discourse/components/user-stream.js.es6 b/app/assets/javascripts/discourse/components/user-stream.js.es6 index ad38f8e0405..2afce0b9787 100644 --- a/app/assets/javascripts/discourse/components/user-stream.js.es6 +++ b/app/assets/javascripts/discourse/components/user-stream.js.es6 @@ -1,4 +1,5 @@ import LoadMore from "discourse/mixins/load-more"; +import ClickTrack from 'discourse/lib/click-track'; export default Ember.Component.extend(LoadMore, { loading: false, @@ -9,6 +10,38 @@ export default Ember.Component.extend(LoadMore, { Em.run.schedule('afterRender', () => $(document).scrollTop(0)); }.observes('stream.user.id'), + _inserted: function() { + this.bindScrolling({name: 'user-stream-view'}); + + $(window).on('resize.discourse-on-scroll', () => this.scrolled()); + + this.$().on('mouseup.discourse-redirect', '.excerpt a', function(e) { + // bypass if we are selecting stuff + const selection = window.getSelection && window.getSelection(); + if (selection.type === "Range" || selection.rangeCount > 0) { + if (Discourse.Utilities.selectedText() !== "") { + return true; + } + } + + const $target = $(e.target); + if ($target.hasClass('mention') || $target.parents('.expanded-embed').length) { return false; } + + return ClickTrack.trackClick(e); + }); + + }.on('didInsertElement'), + + // This view is being removed. Shut down operations + _destroyed: function() { + this.unbindScrolling('user-stream-view'); + $(window).unbind('resize.discourse-on-scroll'); + + // Unbind link tracking + this.$().off('mouseup.discourse-redirect', '.excerpt a'); + + }.on('willDestroyElement'), + actions: { loadMore() { if (this.get('loading')) { return; } diff --git a/app/assets/javascripts/discourse/lib/click-track.js.es6 b/app/assets/javascripts/discourse/lib/click-track.js.es6 index cade30d7408..b8e56f13f7a 100644 --- a/app/assets/javascripts/discourse/lib/click-track.js.es6 +++ b/app/assets/javascripts/discourse/lib/click-track.js.es6 @@ -15,9 +15,9 @@ export default { if ($link.hasClass('lightbox') || $link.hasClass('mention-group') || $link.hasClass('no-track-link')) { return true; } var href = $link.attr('href') || $link.data('href'), - $article = $link.closest('article'), + $article = $link.closest('article,.excerpt'), postId = $article.data('post-id'), - topicId = $('#topic').data('topic-id'), + topicId = $('#topic').data('topic-id') || $article.data('topic-id'), userId = $link.data('user-id'); if (!href || href.trim().length === 0 || href.indexOf("mailto:") === 0) { return; } diff --git a/app/assets/javascripts/discourse/templates/components/stream-item.hbs b/app/assets/javascripts/discourse/templates/components/stream-item.hbs index 4c5609b88db..0018f8a2d84 100644 --- a/app/assets/javascripts/discourse/templates/components/stream-item.hbs +++ b/app/assets/javascripts/discourse/templates/components/stream-item.hbs @@ -13,7 +13,7 @@

{{actionDescription}}

{{/if}} -

{{{item.excerpt}}}

+

{{{item.excerpt}}}

{{#each item.children as |child|}}
diff --git a/test/javascripts/lib/click-track-profile-page-test.js.es6 b/test/javascripts/lib/click-track-profile-page-test.js.es6 new file mode 100644 index 00000000000..d224421b2b5 --- /dev/null +++ b/test/javascripts/lib/click-track-profile-page-test.js.es6 @@ -0,0 +1,206 @@ +import { blank } from 'helpers/qunit-helpers'; +import DiscourseURL from "discourse/lib/url"; +import ClickTrack from "discourse/lib/click-track"; + +var windowOpen, + win, + redirectTo; + +module("lib:click-track-profile-page", { + setup: function() { + + // Prevent any of these tests from navigating away + win = {focus: function() { } }; + redirectTo = sandbox.stub(DiscourseURL, "redirectTo"); + sandbox.stub(Discourse, "ajax"); + windowOpen = sandbox.stub(window, "open").returns(win); + sandbox.stub(win, "focus"); + + fixture().html( + `

+ google.com + google.com +

+ google.com1 + google.com1 +
+ google.com + forum + log.txt + #hashtag +

+

+ google.com + google.com +

+ google.com1 + google.com1 +
+ google.com + forum + log.txt + #hashtag +

`); + } +}); + +var track = ClickTrack.trackClick; + +// test +var generateClickEventOn = function(selector) { + return $.Event("click", { currentTarget: fixture(selector)[0] }); +}; + +test("does not track clicks on lightboxes", function() { + var clickEvent = generateClickEventOn('.lightbox'); + 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'); + sandbox.stub(clickEvent, "preventDefault"); + track(clickEvent); + ok(clickEvent.preventDefault.calledOnce); + ok(DiscourseURL.redirectTo.calledOnce); +}); + +test("does not track clicks when forcibly disabled", function() { + ok(track(generateClickEventOn('.no-track-link'))); +}); + +test("does not track clicks on back buttons", function() { + ok(track(generateClickEventOn('.back'))); +}); + +test("does not track clicks on quote buttons", function() { + ok(track(generateClickEventOn('.quote-other-topic'))); +}); + +test("does not track clicks on category badges", () => { + ok(!track(generateClickEventOn('.hashtag'))); +}); + +test("removes the href and put it as a data attribute", function() { + track(generateClickEventOn('a')); + + var $link = fixture('a').first(); + ok($link.hasClass('no-href')); + equal($link.data('href'), 'http://www.google.com'); + blank($link.attr('href')); + ok($link.data('auto-route')); + ok(DiscourseURL.redirectTo.calledOnce); +}); + +asyncTestDiscourse("restores the href after a while", function() { + expect(1); + + track(generateClickEventOn('a')); + + setTimeout(function() { + start(); + equal(fixture('a').attr('href'), "http://www.google.com"); + }, 75); +}); + +var trackRightClick = function(target) { + var clickEvent = generateClickEventOn(target); + clickEvent.which = 3; + return track(clickEvent); +}; + +test("right clicks change the href", function() { + ok(trackRightClick('a')); + equal(fixture('a').first().prop('href'), "http://www.google.com/"); +}); + +test("right clicks are tracked", function() { + Discourse.SiteSettings.track_external_right_clicks = true; + trackRightClick('a'); + equal(fixture('.first a').first().attr('href'), "/clicks/track?url=http%3A%2F%2Fwww.google.com&post_id=42&topic_id=1337"); +}); + +test("right clicks are tracked for second excerpt", function() { + Discourse.SiteSettings.track_external_right_clicks = true; + trackRightClick('.second a'); + equal(fixture('.second a').first().attr('href'), "/clicks/track?url=http%3A%2F%2Fwww.google.com&post_id=24&topic_id=7331"); +}); + +test("preventDefault is not called for right clicks", function() { + var clickEvent = generateClickEventOn('a'); + clickEvent.which = 3; + sandbox.stub(clickEvent, "preventDefault"); + ok(track(clickEvent)); + ok(!clickEvent.preventDefault.calledOnce); +}); + +var testOpenInANewTab = function(description, clickEventModifier) { + test(description, function() { + var clickEvent = generateClickEventOn('a'); + clickEventModifier(clickEvent); + sandbox.stub(clickEvent, "preventDefault"); + ok(track(clickEvent)); + ok(Discourse.ajax.calledOnce); + ok(!clickEvent.preventDefault.calledOnce); + }); +}; + +testOpenInANewTab("it opens in a new tab when pressing shift", function(clickEvent) { + clickEvent.shiftKey = true; +}); + +testOpenInANewTab("it opens in a new tab when pressing meta", function(clickEvent) { + clickEvent.metaKey = true; +}); + +testOpenInANewTab("it opens in a new tab when pressing ctrl", function(clickEvent) { + clickEvent.ctrlKey = true; +}); + +testOpenInANewTab("it opens in a new tab on middle click", function(clickEvent) { + clickEvent.button = 2; +}); + +test("tracks via AJAX if we're on the same site", function() { + sandbox.stub(DiscourseURL, "routeTo"); + sandbox.stub(DiscourseURL, "origin").returns("http://discuss.domain.com"); + + ok(!track(generateClickEventOn('#same-site'))); + ok(Discourse.ajax.calledOnce); + ok(DiscourseURL.routeTo.calledOnce); +}); + +test("does not track via AJAX for attachments", function() { + sandbox.stub(DiscourseURL, "routeTo"); + sandbox.stub(DiscourseURL, "origin").returns("http://discuss.domain.com"); + + ok(!track(generateClickEventOn('.attachment'))); + ok(DiscourseURL.redirectTo.calledOnce); +}); + +test("tracks custom urls when opening in another window", function() { + var clickEvent = generateClickEventOn('a'); + sandbox.stub(Discourse.User, "currentProp").withArgs('external_links_in_new_tab').returns(true); + ok(!track(clickEvent)); + ok(windowOpen.calledWith('/clicks/track?url=http%3A%2F%2Fwww.google.com&post_id=42&topic_id=1337', '_blank')); +}); + +test("tracks custom urls on second excerpt when opening in another window", function() { + var clickEvent = generateClickEventOn('.second a'); + sandbox.stub(Discourse.User, "currentProp").withArgs('external_links_in_new_tab').returns(true); + ok(!track(clickEvent)); + ok(windowOpen.calledWith('/clicks/track?url=http%3A%2F%2Fwww.google.com&post_id=24&topic_id=7331', '_blank')); +}); + +test("tracks custom urls when opening in another window", function() { + var clickEvent = generateClickEventOn('a'); + ok(!track(clickEvent)); + ok(redirectTo.calledWith('/clicks/track?url=http%3A%2F%2Fwww.google.com&post_id=42&topic_id=1337')); +}); + +test("tracks custom urls on second excerpt when opening in another window", function() { + var clickEvent = generateClickEventOn('.second a'); + ok(!track(clickEvent)); + ok(redirectTo.calledWith('/clicks/track?url=http%3A%2F%2Fwww.google.com&post_id=24&topic_id=7331')); +}); diff --git a/test/javascripts/lib/click-track-test.js.es6 b/test/javascripts/lib/click-track-test.js.es6 index 2bcfc673e02..305ae0664ba 100644 --- a/test/javascripts/lib/click-track-test.js.es6 +++ b/test/javascripts/lib/click-track-test.js.es6 @@ -17,7 +17,7 @@ module("lib:click-track", { sandbox.stub(win, "focus"); fixture().html( - `
+ `
google.com google.com @@ -132,7 +132,7 @@ test("right clicks change the href", function() { test("right clicks are tracked", function() { Discourse.SiteSettings.track_external_right_clicks = true; trackRightClick(); - equal(fixture('a').first().attr('href'), "/clicks/track?url=http%3A%2F%2Fwww.google.com&post_id=42"); + equal(fixture('a').first().attr('href'), "/clicks/track?url=http%3A%2F%2Fwww.google.com&post_id=42&topic_id=1337"); }); test("preventDefault is not called for right clicks", function() { @@ -191,11 +191,11 @@ test("tracks custom urls when opening in another window", function() { var clickEvent = generateClickEventOn('a'); sandbox.stub(Discourse.User, "currentProp").withArgs('external_links_in_new_tab').returns(true); ok(!track(clickEvent)); - ok(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&topic_id=1337', '_blank')); }); test("tracks custom urls when opening in another window", function() { var clickEvent = generateClickEventOn('a'); ok(!track(clickEvent)); - ok(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&topic_id=1337')); });