From b7b5caa50ed157c9af1a638bde7c57f3ce3ba44b Mon Sep 17 00:00:00 2001 From: cpradio <forums@cpradio.com> Date: Mon, 2 May 2016 14:48:34 -0400 Subject: [PATCH] FEATURE: Apply external window setting to Revision History (#4207) --- .../discourse/lib/click-track.js.es6 | 2 +- .../discourse/templates/modal/history.hbs | 2 +- .../discourse/views/history.js.es6 | 26 ++- .../lib/click-track-edit-history-test.js.es6 | 193 ++++++++++++++++++ 4 files changed, 220 insertions(+), 3 deletions(-) create mode 100644 test/javascripts/lib/click-track-edit-history-test.js.es6 diff --git a/app/assets/javascripts/discourse/lib/click-track.js.es6 b/app/assets/javascripts/discourse/lib/click-track.js.es6 index b8e56f13f7a..b36e97cdf89 100644 --- a/app/assets/javascripts/discourse/lib/click-track.js.es6 +++ b/app/assets/javascripts/discourse/lib/click-track.js.es6 @@ -15,7 +15,7 @@ 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,.excerpt'), + $article = $link.closest('article,.excerpt,#revisions'), postId = $article.data('post-id'), topicId = $('#topic').data('topic-id') || $article.data('topic-id'), userId = $link.data('user-id'); diff --git a/app/assets/javascripts/discourse/templates/modal/history.hbs b/app/assets/javascripts/discourse/templates/modal/history.hbs index 72857dbf865..8a5303fd0c0 100644 --- a/app/assets/javascripts/discourse/templates/modal/history.hbs +++ b/app/assets/javascripts/discourse/templates/modal/history.hbs @@ -44,7 +44,7 @@ {{/if}} {{/unless}} </div> - <div id="revisions" {{bind-attr class="hiddenClasses"}}> + <div id="revisions" data-post-id="{{model.post_id}}" {{bind-attr class="hiddenClasses"}}> {{#if model.title_changes}} <div class="row"> <h2>{{{titleDiff}}}</h2> diff --git a/app/assets/javascripts/discourse/views/history.js.es6 b/app/assets/javascripts/discourse/views/history.js.es6 index 7bec4d846e1..54e9ab3e3be 100644 --- a/app/assets/javascripts/discourse/views/history.js.es6 +++ b/app/assets/javascripts/discourse/views/history.js.es6 @@ -1,4 +1,5 @@ import ModalBodyView from "discourse/views/modal-body"; +import ClickTrack from 'discourse/lib/click-track'; export default ModalBodyView.extend({ templateName: 'modal/history', @@ -7,5 +8,28 @@ export default ModalBodyView.extend({ resizeModal: function(){ const viewPortHeight = $(window).height(); this.$(".modal-body").css("max-height", Math.floor(0.8 * viewPortHeight) + "px"); - }.on("didInsertElement") + }.on("didInsertElement"), + + _inserted: function() { + this.$().on('mouseup.discourse-redirect', '#revisions 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.$().off('mouseup.discourse-redirect', '#revisions a'); + }.on('willDestroyElement') }); diff --git a/test/javascripts/lib/click-track-edit-history-test.js.es6 b/test/javascripts/lib/click-track-edit-history-test.js.es6 new file mode 100644 index 00000000000..d7fa2623431 --- /dev/null +++ b/test/javascripts/lib/click-track-edit-history-test.js.es6 @@ -0,0 +1,193 @@ +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-edit-history", { + 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( + `<div id="topic" data-topic-id="1337"> + </div> + <div id="revisions" data-post-id="42" class=""> + <div class="row"> + <div class="span8"> + <a href="http://www.google.com">google.com</a> + <a class="lightbox back quote-other-topic" href="http://www.google.com">google.com</a> + <div class="onebox-result"> + <a id="inside-onebox" href="http://www.google.com">google.com<span class="badge">1</span></a> + <a id="inside-onebox-forced" class="track-link" href="http://www.google.com">google.com<span class="badge">1</span></a> + </div> + <a class="no-track-link" href="http://www.google.com">google.com</a> + <a id="same-site" href="http://discuss.domain.com">forum</a> + <a class="attachment" href="http://discuss.domain.com/uploads/default/1234/1532357280.txt">log.txt</a> + <a class="hashtag" href="http://discuss.domain.com">#hashtag</a> + </div> + <div class="span8 offset1"> + <a href="http://www.google.com">google.com</a> + <a class="lightbox back quote-other-topic" href="http://www.google.com">google.com</a> + <div class="onebox-result"> + <a id="inside-onebox" href="http://www.google.com">google.com<span class="badge">1</span></a> + <a id="inside-onebox-forced" class="track-link" href="http://www.google.com">google.com<span class="badge">1</span></a> + </div> + <a class="no-track-link" href="http://www.google.com">google.com</a> + <a id="same-site" href="http://discuss.domain.com">forum</a> + <a class="attachment" href="http://discuss.domain.com/uploads/default/1234/1532357280.txt">log.txt</a> + <a class="hashtag" href="http://discuss.domain.com">#hashtag</a> + </div> + </div> + </div>`); + } +}); + +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('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() { + 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 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')); +});