Merge pull request #5708 from jhollingsworth/feature/multiline-blob-select
Enable multiline select for blobs.
This commit is contained in:
commit
db0c353a78
3 changed files with 205 additions and 9 deletions
|
@ -1,24 +1,76 @@
|
|||
class BlobView
|
||||
constructor: ->
|
||||
# handle multi-line select
|
||||
handleMultiSelect = (e) ->
|
||||
[ first_line, last_line ] = parseSelectedLines()
|
||||
[ line_number ] = parseSelectedLines($(this).attr("id"))
|
||||
hash = "L#{line_number}"
|
||||
|
||||
if e.shiftKey and not isNaN(first_line) and not isNaN(line_number)
|
||||
if line_number < first_line
|
||||
last_line = first_line
|
||||
first_line = line_number
|
||||
else
|
||||
last_line = line_number
|
||||
|
||||
hash = if first_line == last_line then "L#{first_line}" else "L#{first_line}-#{last_line}"
|
||||
|
||||
setHash(hash)
|
||||
e.preventDefault()
|
||||
|
||||
# See if there are lines selected
|
||||
# "#L12" and "#L34-56" supported
|
||||
highlightBlobLines = ->
|
||||
if window.location.hash isnt ""
|
||||
matches = window.location.hash.match(/\#L(\d+)(\-(\d+))?/)
|
||||
highlightBlobLines = (e) ->
|
||||
[ first_line, last_line ] = parseSelectedLines()
|
||||
|
||||
unless isNaN first_line
|
||||
$("#tree-content-holder .highlight .line").removeClass("hll")
|
||||
$("#LC#{line}").addClass("hll") for line in [first_line..last_line]
|
||||
$("#L#{first_line}").ScrollTo() unless e?
|
||||
|
||||
# parse selected lines from hash
|
||||
# always return first and last line (initialized to NaN)
|
||||
parseSelectedLines = (str) ->
|
||||
first_line = NaN
|
||||
last_line = NaN
|
||||
hash = str || window.location.hash
|
||||
|
||||
if hash isnt ""
|
||||
matches = hash.match(/\#?L(\d+)(\-(\d+))?/)
|
||||
first_line = parseInt(matches?[1])
|
||||
last_line = parseInt(matches?[3])
|
||||
last_line = first_line if isNaN(last_line)
|
||||
|
||||
unless isNaN first_line
|
||||
last_line = first_line if isNaN(last_line)
|
||||
$("#tree-content-holder .highlight .line").removeClass("hll")
|
||||
$("#LC#{line}").addClass("hll") for line in [first_line..last_line]
|
||||
$("#L#{first_line}").ScrollTo()
|
||||
[ first_line, last_line ]
|
||||
|
||||
setHash = (hash) ->
|
||||
hash = hash.replace(/^\#/, "")
|
||||
nodes = $("#" + hash)
|
||||
# if any nodes are using this id, they must be temporarily changed
|
||||
# also, add a temporary div at the top of the screen to prevent scrolling
|
||||
if nodes.length > 0
|
||||
scroll_top = $(document).scrollTop()
|
||||
nodes.attr("id", "")
|
||||
tmp = $("<div></div>")
|
||||
.css({ position: "absolute", visibility: "hidden", top: scroll_top + "px" })
|
||||
.attr("id", hash)
|
||||
.appendTo(document.body)
|
||||
|
||||
window.location.hash = hash
|
||||
|
||||
# restore the nodes
|
||||
if nodes.length > 0
|
||||
tmp.remove()
|
||||
nodes.attr("id", hash)
|
||||
|
||||
# initialize multi-line select
|
||||
$("#tree-content-holder .line_numbers a[id^=L]").on("click", handleMultiSelect)
|
||||
|
||||
# Highlight the correct lines on load
|
||||
highlightBlobLines()
|
||||
|
||||
# Highlight the correct lines when the hash part of the URL changes
|
||||
$(window).on 'hashchange', highlightBlobLines
|
||||
$(window).on("hashchange", highlightBlobLines)
|
||||
|
||||
|
||||
@BlobView = BlobView
|
||||
|
|
86
features/project/source/multiselect_blob.feature
Normal file
86
features/project/source/multiselect_blob.feature
Normal file
|
@ -0,0 +1,86 @@
|
|||
Feature: Project Multiselect Blob
|
||||
Background:
|
||||
Given I sign in as a user
|
||||
And I own project "Shop"
|
||||
And I visit project source page
|
||||
And I click on "Gemfile.lock" file in repo
|
||||
|
||||
@javascript
|
||||
Scenario: I click line 1 in file
|
||||
When I click line 1 in file
|
||||
Then I should see "L1" as URI fragment
|
||||
And I should see line 1 highlighted
|
||||
|
||||
@javascript
|
||||
Scenario: I shift-click line 1 in file
|
||||
When I shift-click line 1 in file
|
||||
Then I should see "L1" as URI fragment
|
||||
And I should see line 1 highlighted
|
||||
|
||||
@javascript
|
||||
Scenario: I click line 1 then click line 2 in file
|
||||
When I click line 1 in file
|
||||
Then I should see "L1" as URI fragment
|
||||
And I should see line 1 highlighted
|
||||
Then I click line 2 in file
|
||||
Then I should see "L2" as URI fragment
|
||||
And I should see line 2 highlighted
|
||||
|
||||
@javascript
|
||||
Scenario: I click various line numbers to test multiselect
|
||||
Then I click line 1 in file
|
||||
Then I should see "L1" as URI fragment
|
||||
And I should see line 1 highlighted
|
||||
Then I shift-click line 2 in file
|
||||
Then I should see "L1-2" as URI fragment
|
||||
And I should see lines 1-2 highlighted
|
||||
Then I shift-click line 3 in file
|
||||
Then I should see "L1-3" as URI fragment
|
||||
And I should see lines 1-3 highlighted
|
||||
Then I click line 3 in file
|
||||
Then I should see "L3" as URI fragment
|
||||
And I should see line 3 highlighted
|
||||
Then I shift-click line 1 in file
|
||||
Then I should see "L1-3" as URI fragment
|
||||
And I should see lines 1-3 highlighted
|
||||
Then I shift-click line 5 in file
|
||||
Then I should see "L1-5" as URI fragment
|
||||
And I should see lines 1-5 highlighted
|
||||
Then I shift-click line 4 in file
|
||||
Then I should see "L1-4" as URI fragment
|
||||
And I should see lines 1-4 highlighted
|
||||
Then I click line 5 in file
|
||||
Then I should see "L5" as URI fragment
|
||||
And I should see line 5 highlighted
|
||||
Then I shift-click line 3 in file
|
||||
Then I should see "L3-5" as URI fragment
|
||||
And I should see lines 3-5 highlighted
|
||||
Then I shift-click line 1 in file
|
||||
Then I should see "L1-3" as URI fragment
|
||||
And I should see lines 1-3 highlighted
|
||||
Then I shift-click line 1 in file
|
||||
Then I should see "L1" as URI fragment
|
||||
And I should see line 1 highlighted
|
||||
|
||||
@javascript
|
||||
Scenario: I multiselect lines 1-5 and then go back and forward in history
|
||||
When I click line 1 in file
|
||||
And I shift-click line 3 in file
|
||||
And I shift-click line 2 in file
|
||||
And I shift-click line 5 in file
|
||||
Then I should see "L1-5" as URI fragment
|
||||
And I should see lines 1-5 highlighted
|
||||
Then I go back in history
|
||||
Then I should see "L1-2" as URI fragment
|
||||
And I should see lines 1-2 highlighted
|
||||
Then I go back in history
|
||||
Then I should see "L1-3" as URI fragment
|
||||
And I should see lines 1-3 highlighted
|
||||
Then I go back in history
|
||||
Then I should see "L1" as URI fragment
|
||||
And I should see line 1 highlighted
|
||||
Then I go forward in history
|
||||
And I go forward in history
|
||||
And I go forward in history
|
||||
Then I should see "L1-5" as URI fragment
|
||||
And I should see lines 1-5 highlighted
|
58
features/steps/project/project_multiselect_blob.rb
Normal file
58
features/steps/project/project_multiselect_blob.rb
Normal file
|
@ -0,0 +1,58 @@
|
|||
class ProjectMultiselectBlob < Spinach::FeatureSteps
|
||||
include SharedAuthentication
|
||||
include SharedProject
|
||||
include SharedPaths
|
||||
|
||||
class << self
|
||||
def click_line_steps(*line_numbers)
|
||||
line_numbers.each do |line_number|
|
||||
step "I click line #{line_number} in file" do
|
||||
find("#L#{line_number}").click
|
||||
end
|
||||
|
||||
step "I shift-click line #{line_number} in file" do
|
||||
script = "$('#L#{line_number}').trigger($.Event('click', { shiftKey: true }));"
|
||||
page.evaluate_script(script)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def check_state_steps(*ranges)
|
||||
ranges.each do |range|
|
||||
fragment = range.kind_of?(Array) ? "L#{range.first}-#{range.last}" : "L#{range}"
|
||||
pluralization = range.kind_of?(Array) ? "s" : ""
|
||||
|
||||
step "I should see \"#{fragment}\" as URI fragment" do
|
||||
URI.parse(current_url).fragment.should == fragment
|
||||
end
|
||||
|
||||
step "I should see line#{pluralization} #{fragment[1..-1]} highlighted" do
|
||||
ids = Array(range).map { |n| "LC#{n}" }
|
||||
extra = false
|
||||
|
||||
highlighted = all("#tree-content-holder .highlight .line.hll")
|
||||
highlighted.each do |element|
|
||||
extra ||= ids.delete(element[:id]).nil?
|
||||
end
|
||||
|
||||
extra.should be_false and ids.should be_empty
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
click_line_steps *Array(1..5)
|
||||
check_state_steps *Array(1..5), Array(1..2), Array(1..3), Array(1..4), Array(1..5), Array(3..5)
|
||||
|
||||
step 'I go back in history' do
|
||||
page.evaluate_script("window.history.back()")
|
||||
end
|
||||
|
||||
step 'I go forward in history' do
|
||||
page.evaluate_script("window.history.forward()")
|
||||
end
|
||||
|
||||
step 'I click on "Gemfile.lock" file in repo' do
|
||||
click_link "Gemfile.lock"
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue