From c9e0f07a5a4a2f9512872ba416d5f583a007793e Mon Sep 17 00:00:00 2001 From: Damien Mathieu <42@dmathieu.com> Date: Tue, 7 Jan 2014 11:18:15 +0100 Subject: [PATCH 1/3] highlight multiple lines We can now highlight multiple lines, adding #L1-L2 to the hash. We can select the ending line with shift + click. Closes travis-ci/travis-ci#1829 --- assets/scripts/app/controllers/build.coffee | 2 +- assets/scripts/app/controllers/job.coffee | 2 +- assets/scripts/app/controllers/repo.coffee | 10 +++ assets/scripts/app/routes.coffee | 5 +- assets/scripts/app/views/log.coffee | 64 ++++++++++++------- .../lib/travis/line_number_parser.coffee | 15 ++++- .../spec/unit/line_number_parser_spec.coffee | 12 ++++ assets/styles/_mixins/colors.sass | 2 + assets/styles/main/log.sass | 2 + 9 files changed, 86 insertions(+), 28 deletions(-) create mode 100644 assets/scripts/spec/unit/line_number_parser_spec.coffee diff --git a/assets/scripts/app/controllers/build.coffee b/assets/scripts/app/controllers/build.coffee index ba99f348..1efa56bd 100644 --- a/assets/scripts/app/controllers/build.coffee +++ b/assets/scripts/app/controllers/build.coffee @@ -2,7 +2,7 @@ Travis.BuildController = Ember.Controller.extend needs: ['repo'] repoBinding: 'controllers.repo.repo' commitBinding: 'build.commit' - lineNumberBinding: 'controllers.repo.lineNumber' + lineNumbersBinding: 'controllers.repo.lineNumbers' currentUserBinding: 'controllers.repo.currentUser' tabBinding: 'controllers.repo.tab' diff --git a/assets/scripts/app/controllers/job.coffee b/assets/scripts/app/controllers/job.coffee index 148dbad7..92e97862 100644 --- a/assets/scripts/app/controllers/job.coffee +++ b/assets/scripts/app/controllers/job.coffee @@ -4,7 +4,7 @@ Travis.JobController = Em.Controller.extend jobBinding: 'controllers.repo.job' repoBinding: 'controllers.repo.repo' commitBinding: 'job.commit' - lineNumberBinding: 'controllers.repo.lineNumber' + lineNumbersBinding: 'controllers.repo.lineNumbers' currentUserBinding: 'controllers.repo.currentUser' tabBinding: 'controllers.repo.tab' diff --git a/assets/scripts/app/controllers/repo.coffee b/assets/scripts/app/controllers/repo.coffee index 88276d71..cbd4fa34 100644 --- a/assets/scripts/app/controllers/repo.coffee +++ b/assets/scripts/app/controllers/repo.coffee @@ -72,3 +72,13 @@ Travis.RepoController = Travis.Controller.extend urlGithub: (-> Travis.Urls.githubRepo(@get('repo.slug')) ).property('repo.slug') + + setLineNumbers: (start, end) -> + lines = [] + index = start + + while index <= (end || start) + lines.push(index) + index++ + + @set('lineNumbers', lines) diff --git a/assets/scripts/app/routes.coffee b/assets/scripts/app/routes.coffee index 0f8186c1..6907527d 100644 --- a/assets/scripts/app/routes.coffee +++ b/assets/scripts/app/routes.coffee @@ -82,7 +82,7 @@ Ember.Route.reopen Travis.Router.reopen transitionTo: -> - this.container.lookup('controller:repo').set('lineNumber', null) + this.container.lookup('controller:repo').set('lineNumbers', []) @_super.apply this, arguments @@ -113,7 +113,8 @@ Travis.ApplicationRoute = Ember.Route.extend Travis.LineNumberParser, setupController: -> @_super.apply this, arguments - this.controllerFor('repo').set('lineNumber', @fetchLineNumber()) + line_numbers = @fetchLineNumbers(document.location.hash) + this.controllerFor('repo').setLineNumbers line_numbers[0], line_numbers[1] Travis.SetupLastBuild = Ember.Mixin.create setupController: -> diff --git a/assets/scripts/app/views/log.coffee b/assets/scripts/app/views/log.coffee index 2bacdfe2..f2216ad1 100644 --- a/assets/scripts/app/views/log.coffee +++ b/assets/scripts/app/views/log.coffee @@ -26,7 +26,7 @@ Travis.reopen console.log 'log view: did insert' if Log.DEBUG @_super.apply this, arguments @createEngine() - @lineNumberDidChange() + @lineNumbersDidChange() willDestroyElement: -> console.log 'log view: will destroy' if Log.DEBUG @@ -63,9 +63,9 @@ Travis.reopen @engine.set(part.number, part.content) @propertyDidChange('limited') - lineNumberDidChange: (-> - @scroll.set(number) if !@get('isDestroyed') && number = @get('controller.lineNumber') - ).observes('controller.lineNumber') + lineNumbersDidChange: (-> + @scroll.set(numbers) if !@get('isDestroyed') && numbers = @get('controller.lineNumbers') + ).observes('controller.lineNumbers') limited: (-> @engine?.limit?.limited @@ -80,22 +80,35 @@ Travis.reopen event.preventDefault() numberLineOnHover: -> - $('#log').on 'mouseenter', 'a', -> - $(@).attr('href', '#L' + ($("#log p:visible").index(@parentNode) + 1)) + $('#log').on 'mouseenter', 'a', (event) -> + hovered = $("#log p:visible").index(@parentNode) + 1 + selected = $("#log p:visible").index($('#log p.highlight')) + 1 + + if event.shiftKey + end = "-L#{hovered}" + start = selected + else + start = hovered + end = '' + + $(@).attr('href', "#L#{start}#{end}") click: (event) -> - if (href = $(event.target).attr('href')) && matches = href?.match(/#L(\d+)$/) - @lineNumberClicked(matches[1]) + if (href = $(event.target).attr('href')) && matches = href?.match(Travis.LineNumberRegex) + lines = [matches[1], matches[3]].sort (a, b) -> a - b + + @lineNumberClicked(lines[0], lines[1]) event.stopPropagation() false else target = $(event.target) target.closest('.fold').toggleClass('open') - lineNumberClicked: (number) -> - path = "#{window.location.pathname}#L#{number}" + lineNumberClicked: (start, end) -> + second_number = if end then "-L#{end}" else '' + path = "#{window.location.pathname}#L#{start}#{second_number}" window.history.pushState({ path: path }, null, path); - @set('controller.lineNumber', number) + @get('controller.controllers.repo').setLineNumbers(start, end) actions: toTop: () -> @@ -105,25 +118,32 @@ Travis.reopen Log.Scroll = -> Log.Scroll.prototype = $.extend new Log.Listener, - set: (number) -> - return unless number - @number = number + set: (numbers) -> + return unless numbers.length > 0 + @numbers = numbers @tryScroll() insert: (log, data, pos) -> - @tryScroll() if @number + @tryScroll() if @numbers true tryScroll: -> - if element = $("#log p:visible")[@number - 1] + @removeHighlights() + @scrollToFirstLine() + + first_line = @numbers[0] - 1 + last_line = @numbers[@numbers.length - 1] + + $('#log').find('p:visible').slice(first_line, last_line).addClass('highlight') + @numbers = undefined + + removeHighlights: -> + $('#log p.highlight').removeClass('highlight') + + scrollToFirstLine: -> + if element = $("#log p:visible")[@numbers[0] - 1] $('#main').scrollTop(0) $('html, body').scrollTop($(element).offset()?.top) # weird, html works in chrome, body in firefox - @highlight(element) - @number = undefined - - highlight: (element) -> - $('#log p.highlight').removeClass('highlight') - $(element).addClass('highlight') # Log.Logger = -> # Log.Logger.prototype = $.extend new Log.Listener, diff --git a/assets/scripts/lib/travis/line_number_parser.coffee b/assets/scripts/lib/travis/line_number_parser.coffee index 2abd54df..8cbc87e2 100644 --- a/assets/scripts/lib/travis/line_number_parser.coffee +++ b/assets/scripts/lib/travis/line_number_parser.coffee @@ -1,3 +1,14 @@ +Travis.LineNumberRegex = /#L(\d+)(-L(\d+))?$/ Travis.LineNumberParser = Ember.Mixin.create - fetchLineNumber: -> - match[1] if match = document.location.hash.match(/#L(\d+)$/) + + fetchLineNumbers: (hash) -> + if match = hash.match(Travis.LineNumberRegex) + start = match[1] + end = match[3] + + if end? + [start, end] + else + [start] + else + [] diff --git a/assets/scripts/spec/unit/line_number_parser_spec.coffee b/assets/scripts/spec/unit/line_number_parser_spec.coffee new file mode 100644 index 00000000..e55e15e1 --- /dev/null +++ b/assets/scripts/spec/unit/line_number_parser_spec.coffee @@ -0,0 +1,12 @@ +object = Ember.Object.extend(Travis.LineNumberParser) +subject = object.create() + +module "Travis.LineNumberParser", + test "without line numbers", -> + deepEqual subject.fetchLineNumbers(''), [] + + test "with a start date only", -> + deepEqual subject.fetchLineNumbers('#L5'), ['5'] + + test "with a start and end dates", -> + deepEqual subject.fetchLineNumbers('#L5-L6'), ['5', '6'] diff --git a/assets/styles/_mixins/colors.sass b/assets/styles/_mixins/colors.sass index e54bf4fa..ec6e5313 100644 --- a/assets/styles/_mixins/colors.sass +++ b/assets/styles/_mixins/colors.sass @@ -23,6 +23,7 @@ $yellow-light-2: #fffcf4 $gray-dark-1: #333 $gray-dark-2: #444 $gray-dark-3: #666 +$gray-dark-4: #777 $gray-medium-1: #999 $gray-medium-2: #aaa $gray-medium-3: #c4cbcc @@ -65,6 +66,7 @@ $color-bg-log: #222222 $color-bg-log-fold: $gray-dark-1 $color-bg-log-hover: $gray-dark-2 $color-bg-log-highlight: $gray-dark-3 +$color-bg-log-fold-highlight: $gray-dark-4 $color-bg-slider: $slate-blue-3 $color-bg-left: $gray-light-4 $color-bg-list-odd: $white diff --git a/assets/styles/main/log.sass b/assets/styles/main/log.sass index 2e0ad5ff..d5793a54 100644 --- a/assets/styles/main/log.sass +++ b/assets/styles/main/log.sass @@ -57,6 +57,8 @@ pre#log // &.active p:first-of-type background: $color-bg-log-fold inline-image('ui/log.fold.open.2.png') no-repeat 8px 3px + &.highlight + background-color: $color-bg-log-fold-highlight &:not(.open) p:first-of-type visibility: visible From ff1aad3f038a145e343d12a1e6ef7e0bf9c33dd6 Mon Sep 17 00:00:00 2001 From: Damien Mathieu <42@dmathieu.com> Date: Thu, 9 Jan 2014 15:43:19 +0100 Subject: [PATCH 2/3] extract the log lines selector into a separate component --- assets/scripts/app/controllers/build.coffee | 1 - assets/scripts/app/controllers/job.coffee | 1 - assets/scripts/app/controllers/repo.coffee | 10 --- assets/scripts/app/routes.coffee | 14 ---- assets/scripts/app/views/log.coffee | 61 ++-------------- .../lib/travis/line_number_parser.coffee | 14 ---- .../scripts/lib/travis/lines_selector.coffee | 53 ++++++++++++++ .../spec/unit/line_number_parser_spec.coffee | 12 ---- .../spec/unit/line_selector_spec.coffee | 70 +++++++++++++++++++ 9 files changed, 130 insertions(+), 106 deletions(-) delete mode 100644 assets/scripts/lib/travis/line_number_parser.coffee create mode 100644 assets/scripts/lib/travis/lines_selector.coffee delete mode 100644 assets/scripts/spec/unit/line_number_parser_spec.coffee create mode 100644 assets/scripts/spec/unit/line_selector_spec.coffee diff --git a/assets/scripts/app/controllers/build.coffee b/assets/scripts/app/controllers/build.coffee index 1efa56bd..6e61ab6f 100644 --- a/assets/scripts/app/controllers/build.coffee +++ b/assets/scripts/app/controllers/build.coffee @@ -2,7 +2,6 @@ Travis.BuildController = Ember.Controller.extend needs: ['repo'] repoBinding: 'controllers.repo.repo' commitBinding: 'build.commit' - lineNumbersBinding: 'controllers.repo.lineNumbers' currentUserBinding: 'controllers.repo.currentUser' tabBinding: 'controllers.repo.tab' diff --git a/assets/scripts/app/controllers/job.coffee b/assets/scripts/app/controllers/job.coffee index 92e97862..7365d06d 100644 --- a/assets/scripts/app/controllers/job.coffee +++ b/assets/scripts/app/controllers/job.coffee @@ -4,7 +4,6 @@ Travis.JobController = Em.Controller.extend jobBinding: 'controllers.repo.job' repoBinding: 'controllers.repo.repo' commitBinding: 'job.commit' - lineNumbersBinding: 'controllers.repo.lineNumbers' currentUserBinding: 'controllers.repo.currentUser' tabBinding: 'controllers.repo.tab' diff --git a/assets/scripts/app/controllers/repo.coffee b/assets/scripts/app/controllers/repo.coffee index cbd4fa34..88276d71 100644 --- a/assets/scripts/app/controllers/repo.coffee +++ b/assets/scripts/app/controllers/repo.coffee @@ -72,13 +72,3 @@ Travis.RepoController = Travis.Controller.extend urlGithub: (-> Travis.Urls.githubRepo(@get('repo.slug')) ).property('repo.slug') - - setLineNumbers: (start, end) -> - lines = [] - index = start - - while index <= (end || start) - lines.push(index) - index++ - - @set('lineNumbers', lines) diff --git a/assets/scripts/app/routes.coffee b/assets/scripts/app/routes.coffee index 6907527d..4739e648 100644 --- a/assets/scripts/app/routes.coffee +++ b/assets/scripts/app/routes.coffee @@ -1,5 +1,4 @@ require 'travis/location' -require 'travis/line_number_parser' Ember.Router.reopen location: (if testMode? then Ember.NoneLocation.create() else Travis.Location.create()) @@ -80,12 +79,6 @@ Ember.Route.reopen Travis.storeAfterSignInPath(path) @transitionTo('auth') -Travis.Router.reopen - transitionTo: -> - this.container.lookup('controller:repo').set('lineNumbers', []) - - @_super.apply this, arguments - Travis.Router.map -> @resource 'index', path: '/', -> @route 'current', path: '/' @@ -109,13 +102,6 @@ Travis.Router.map -> @route 'index', path: '/' @route 'profile', path: '/profile' -Travis.ApplicationRoute = Ember.Route.extend Travis.LineNumberParser, - setupController: -> - @_super.apply this, arguments - - line_numbers = @fetchLineNumbers(document.location.hash) - this.controllerFor('repo').setLineNumbers line_numbers[0], line_numbers[1] - Travis.SetupLastBuild = Ember.Mixin.create setupController: -> @repoDidLoad() diff --git a/assets/scripts/app/views/log.coffee b/assets/scripts/app/views/log.coffee index f2216ad1..631765b3 100644 --- a/assets/scripts/app/views/log.coffee +++ b/assets/scripts/app/views/log.coffee @@ -1,4 +1,5 @@ require 'log' +require 'travis/lines_selector' Log.DEBUG = false Log.LIMIT = 10000 @@ -26,12 +27,12 @@ Travis.reopen console.log 'log view: did insert' if Log.DEBUG @_super.apply this, arguments @createEngine() - @lineNumbersDidChange() willDestroyElement: -> console.log 'log view: will destroy' if Log.DEBUG parts = @get('log.parts') parts.removeArrayObserver(@, didChange: 'partsDidChange', willChange: 'noop') + @lineSelector?.willDestroy() versionDidChange: (-> @rerender() if @get('state') == 'inDOM' @@ -46,8 +47,8 @@ Travis.reopen console.log 'log view: create engine' if Log.DEBUG @scroll = new Log.Scroll @engine = Log.create(limit: Log.LIMIT, listeners: [@scroll]) + @lineSelector = new Travis.LinesSelector(@$().find('#log'), @scroll, window.location) @observeParts() - @numberLineOnHover() observeParts: -> parts = @get('log.parts') @@ -63,10 +64,6 @@ Travis.reopen @engine.set(part.number, part.content) @propertyDidChange('limited') - lineNumbersDidChange: (-> - @scroll.set(numbers) if !@get('isDestroyed') && numbers = @get('controller.lineNumbers') - ).observes('controller.lineNumbers') - limited: (-> @engine?.limit?.limited ).property() @@ -79,37 +76,11 @@ Travis.reopen Travis.tailing.toggle() event.preventDefault() - numberLineOnHover: -> - $('#log').on 'mouseenter', 'a', (event) -> - hovered = $("#log p:visible").index(@parentNode) + 1 - selected = $("#log p:visible").index($('#log p.highlight')) + 1 - - if event.shiftKey - end = "-L#{hovered}" - start = selected - else - start = hovered - end = '' - - $(@).attr('href', "#L#{start}#{end}") - click: (event) -> - if (href = $(event.target).attr('href')) && matches = href?.match(Travis.LineNumberRegex) - lines = [matches[1], matches[3]].sort (a, b) -> a - b - - @lineNumberClicked(lines[0], lines[1]) - event.stopPropagation() - false - else - target = $(event.target) + target = $(event.target) + if target.prop('tagName') == 'P' target.closest('.fold').toggleClass('open') - lineNumberClicked: (start, end) -> - second_number = if end then "-L#{end}" else '' - path = "#{window.location.pathname}#L#{start}#{second_number}" - window.history.pushState({ path: path }, null, path); - @get('controller.controllers.repo').setLineNumbers(start, end) - actions: toTop: () -> $(window).scrollTop(0) @@ -118,32 +89,14 @@ Travis.reopen Log.Scroll = -> Log.Scroll.prototype = $.extend new Log.Listener, - set: (numbers) -> - return unless numbers.length > 0 - @numbers = numbers - @tryScroll() - insert: (log, data, pos) -> @tryScroll() if @numbers true tryScroll: -> - @removeHighlights() - @scrollToFirstLine() - - first_line = @numbers[0] - 1 - last_line = @numbers[@numbers.length - 1] - - $('#log').find('p:visible').slice(first_line, last_line).addClass('highlight') - @numbers = undefined - - removeHighlights: -> - $('#log p.highlight').removeClass('highlight') - - scrollToFirstLine: -> - if element = $("#log p:visible")[@numbers[0] - 1] + if element = $("#log p:visible.highlight:first") $('#main').scrollTop(0) - $('html, body').scrollTop($(element).offset()?.top) # weird, html works in chrome, body in firefox + $('html, body').scrollTop(element.offset()?.top) # weird, html works in chrome, body in firefox # Log.Logger = -> # Log.Logger.prototype = $.extend new Log.Listener, diff --git a/assets/scripts/lib/travis/line_number_parser.coffee b/assets/scripts/lib/travis/line_number_parser.coffee deleted file mode 100644 index 8cbc87e2..00000000 --- a/assets/scripts/lib/travis/line_number_parser.coffee +++ /dev/null @@ -1,14 +0,0 @@ -Travis.LineNumberRegex = /#L(\d+)(-L(\d+))?$/ -Travis.LineNumberParser = Ember.Mixin.create - - fetchLineNumbers: (hash) -> - if match = hash.match(Travis.LineNumberRegex) - start = match[1] - end = match[3] - - if end? - [start, end] - else - [start] - else - [] diff --git a/assets/scripts/lib/travis/lines_selector.coffee b/assets/scripts/lib/travis/lines_selector.coffee new file mode 100644 index 00000000..1e3cfdc5 --- /dev/null +++ b/assets/scripts/lib/travis/lines_selector.coffee @@ -0,0 +1,53 @@ +class Travis.LinesSelector + element: null + scroll: null + location: null + + constructor: (@element, @scroll, @location) -> + Ember.run.scheduleOnce 'afterRender', this, -> + @highlightLines() + + @element.on 'click', 'a', (event) => + element = $(event.target).parent('p') + @loadLineNumbers(element, event.shiftKey) + + event.preventDefault() + false + + willDestroy: -> + @location.hash = '' + + loadLineNumbers: (element, multiple) -> + @setHashValueWithLine(element, multiple) + @highlightLines() + + highlightLines: -> + @removeAllHighlights() + + if lines = @getSelectedLines() + @element.find('p:visible').slice(lines.first, lines.last).addClass('highlight') + @scroll.tryScroll() + + setHashValueWithLine: (line, multiple) -> + line_number = @getLineNumberFromElement(line) + + if !multiple + hash = "#L#{line_number}" + else + selected_line = @element.find('p:visible.highlight:first')[0] + selected_number = @getLineNumberFromElement(selected_line) + lines = [line_number, selected_number].sort (a,b) -> a - b + hash = "#L#{lines[0]}-L#{lines[1]}" + @location.hash = hash + + getLineNumberFromElement: (element) -> + @element.find('p:visible').index(element) + 1 + + removeAllHighlights: -> + @element.find('p.highlight').removeClass('highlight') + + getSelectedLines: -> + if match = @location.hash.match(/#L(\d+)(-L(\d+))?$/) + first = match[1] - 1 + last = match[3] || match[1] + {first: first, last: last} diff --git a/assets/scripts/spec/unit/line_number_parser_spec.coffee b/assets/scripts/spec/unit/line_number_parser_spec.coffee deleted file mode 100644 index e55e15e1..00000000 --- a/assets/scripts/spec/unit/line_number_parser_spec.coffee +++ /dev/null @@ -1,12 +0,0 @@ -object = Ember.Object.extend(Travis.LineNumberParser) -subject = object.create() - -module "Travis.LineNumberParser", - test "without line numbers", -> - deepEqual subject.fetchLineNumbers(''), [] - - test "with a start date only", -> - deepEqual subject.fetchLineNumbers('#L5'), ['5'] - - test "with a start and end dates", -> - deepEqual subject.fetchLineNumbers('#L5-L6'), ['5', '6'] diff --git a/assets/scripts/spec/unit/line_selector_spec.coffee b/assets/scripts/spec/unit/line_selector_spec.coffee new file mode 100644 index 00000000..6b2c177a --- /dev/null +++ b/assets/scripts/spec/unit/line_selector_spec.coffee @@ -0,0 +1,70 @@ +fakeLocation = {} +fakeScroll = + tryScroll: sinon.spy() + +element = jQuery('
') + +module "Travis.LinesSelector", + setup: -> + fakeLocation.hash = '' + jQuery('body').append(element) + + teardown: -> + element.remove() + +test "defaults to no line selected", -> + Ember.run -> + new Travis.LinesSelector(element, fakeScroll, fakeLocation) + + wait().then -> + equal($('#fakeLog p.highlight').length, 0) + +test "defaults to a single line selected", -> + fakeLocation.hash = '#L2' + Ember.run -> + new Travis.LinesSelector(element, fakeScroll, fakeLocation) + + wait().then -> + equal($('#fakeLog p.highlight').length, 1) + equal($('#fakeLog p:nth-child(2)').hasClass('highlight'), true) + +test "defaults to multiple lines selected", -> + fakeLocation.hash = '#L2-L3' + Ember.run -> + new Travis.LinesSelector(element, fakeScroll, fakeLocation) + + wait().then -> + equal($('#fakeLog p.highlight').length, 2) + equal($('#fakeLog p:nth-child(2)').hasClass('highlight'), true) + equal($('#fakeLog p:nth-child(3)').hasClass('highlight'), true) + +test "selects a single line", -> + Ember.run -> + new Travis.LinesSelector(element, fakeScroll, fakeLocation) + + wait().then -> + equal($('#fakeLog p.highlight').length, 0) + $('#fakeLog p:first a').click() + equal($('#fakeLog p.highlight').length, 1) + equal($('#fakeLog p:nth-child(1)').hasClass('highlight'), true) + equal('#L1', fakeLocation.hash) + +test "selects multiple lines", -> + fakeLocation.hash = '#L2' + Ember.run -> + new Travis.LinesSelector(element, fakeScroll, fakeLocation) + wait().then -> + equal($('#fakeLog p.highlight').length, 1) + + event = jQuery.Event('click') + event.shiftKey = true + $('#fakeLog p:first a').trigger(event) + + equal($('#fakeLog p.highlight').length, 2) + equal($('#fakeLog p:nth-child(1)').hasClass('highlight'), true) + equal($('#fakeLog p:nth-child(2)').hasClass('highlight'), true) + equal('#L1-L2', fakeLocation.hash) From 228afe9a636083a642fdac7171dd40b3b517acfe Mon Sep 17 00:00:00 2001 From: Damien Mathieu <42@dmathieu.com> Date: Thu, 9 Jan 2014 17:31:47 +0100 Subject: [PATCH 3/3] store the last selected line and use it as the other end for multiple selection --- .../scripts/lib/travis/lines_selector.coffee | 18 ++++++++------- .../spec/unit/line_selector_spec.coffee | 22 +++++++++++++++++++ 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/assets/scripts/lib/travis/lines_selector.coffee b/assets/scripts/lib/travis/lines_selector.coffee index 1e3cfdc5..e49a456e 100644 --- a/assets/scripts/lib/travis/lines_selector.coffee +++ b/assets/scripts/lib/travis/lines_selector.coffee @@ -2,9 +2,11 @@ class Travis.LinesSelector element: null scroll: null location: null + last_selected_line: null constructor: (@element, @scroll, @location) -> Ember.run.scheduleOnce 'afterRender', this, -> + @last_selected_line = @getSelectedLines()?.first @highlightLines() @element.on 'click', 'a', (event) => @@ -25,19 +27,19 @@ class Travis.LinesSelector @removeAllHighlights() if lines = @getSelectedLines() - @element.find('p:visible').slice(lines.first, lines.last).addClass('highlight') + @element.find('p:visible').slice(lines.first - 1, lines.last).addClass('highlight') @scroll.tryScroll() setHashValueWithLine: (line, multiple) -> line_number = @getLineNumberFromElement(line) - if !multiple - hash = "#L#{line_number}" - else - selected_line = @element.find('p:visible.highlight:first')[0] - selected_number = @getLineNumberFromElement(selected_line) - lines = [line_number, selected_number].sort (a,b) -> a - b + if multiple && @last_selected_line? + lines = [line_number, @last_selected_line].sort (a,b) -> a - b hash = "#L#{lines[0]}-L#{lines[1]}" + else + hash = "#L#{line_number}" + + @last_selected_line = line_number @location.hash = hash getLineNumberFromElement: (element) -> @@ -48,6 +50,6 @@ class Travis.LinesSelector getSelectedLines: -> if match = @location.hash.match(/#L(\d+)(-L(\d+))?$/) - first = match[1] - 1 + first = match[1] last = match[3] || match[1] {first: first, last: last} diff --git a/assets/scripts/spec/unit/line_selector_spec.coffee b/assets/scripts/spec/unit/line_selector_spec.coffee index 6b2c177a..cbd4f12b 100644 --- a/assets/scripts/spec/unit/line_selector_spec.coffee +++ b/assets/scripts/spec/unit/line_selector_spec.coffee @@ -57,6 +57,7 @@ test "selects multiple lines", -> fakeLocation.hash = '#L2' Ember.run -> new Travis.LinesSelector(element, fakeScroll, fakeLocation) + wait().then -> equal($('#fakeLog p.highlight').length, 1) @@ -68,3 +69,24 @@ test "selects multiple lines", -> equal($('#fakeLog p:nth-child(1)').hasClass('highlight'), true) equal($('#fakeLog p:nth-child(2)').hasClass('highlight'), true) equal('#L1-L2', fakeLocation.hash) + +test "uses the last selected line as second selection line", -> + selector = null + Ember.run -> + selector = new Travis.LinesSelector(element, fakeScroll, fakeLocation) + + wait().then -> + $('#fakeLog p:last a').click() + equal($('#fakeLog p.highlight').length, 1) + equal(3, selector.last_selected_line) + + event = jQuery.Event('click') + event.shiftKey = true + $('#fakeLog p:first a').trigger(event) + + equal($('#fakeLog p.highlight').length, 3) + equal($('#fakeLog p:nth-child(1)').hasClass('highlight'), true) + equal($('#fakeLog p:nth-child(2)').hasClass('highlight'), true) + equal($('#fakeLog p:nth-child(3)').hasClass('highlight'), true) + equal('#L1-L3', fakeLocation.hash) + equal(1, selector.last_selected_line)