summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/application.js.coffee1
-rw-r--r--app/assets/javascripts/dispatcher.js.coffee4
-rw-r--r--app/assets/javascripts/project_find_file.js.coffee125
-rw-r--r--app/assets/javascripts/shortcuts_find_file.js.coffee19
-rw-r--r--app/assets/javascripts/shortcuts_tree.coffee4
-rw-r--r--app/assets/stylesheets/pages/tree.scss8
-rw-r--r--app/controllers/projects/find_file_controller.rb26
-rw-r--r--app/controllers/projects/refs_controller.rb2
-rw-r--r--app/models/repository.rb5
-rw-r--r--app/views/help/_shortcuts.html.haml26
-rw-r--r--app/views/layouts/nav/_project.html.haml3
-rw-r--r--app/views/projects/_find_file_link.html.haml3
-rw-r--r--app/views/projects/find_file/show.html.haml27
-rw-r--r--app/views/projects/tree/show.html.haml8
14 files changed, 254 insertions, 7 deletions
diff --git a/app/assets/javascripts/application.js.coffee b/app/assets/javascripts/application.js.coffee
index b9b095e004a..c095e5ae2b1 100644
--- a/app/assets/javascripts/application.js.coffee
+++ b/app/assets/javascripts/application.js.coffee
@@ -40,6 +40,7 @@
#= require shortcuts_network
#= require jquery.nicescroll.min
#= require_tree .
+#= require fuzzaldrin-plus.min
window.slugify = (text) ->
text.replace(/[^-a-zA-Z0-9]+/g, '_').toLowerCase()
diff --git a/app/assets/javascripts/dispatcher.js.coffee b/app/assets/javascripts/dispatcher.js.coffee
index 69e061ce6e9..58d6b9d4060 100644
--- a/app/assets/javascripts/dispatcher.js.coffee
+++ b/app/assets/javascripts/dispatcher.js.coffee
@@ -87,7 +87,9 @@ class Dispatcher
new GroupAvatar()
when 'projects:tree:show'
new TreeView()
- shortcut_handler = new ShortcutsNavigation()
+ shortcut_handler = new ShortcutsTree()
+ when 'projects:find_file:show'
+ shortcut_handler = true
when 'projects:blob:show'
new LineHighlighter()
shortcut_handler = new ShortcutsNavigation()
diff --git a/app/assets/javascripts/project_find_file.js.coffee b/app/assets/javascripts/project_find_file.js.coffee
new file mode 100644
index 00000000000..0dd32352c34
--- /dev/null
+++ b/app/assets/javascripts/project_find_file.js.coffee
@@ -0,0 +1,125 @@
+class @ProjectFindFile
+ constructor: (@element, @options)->
+ @filePaths = {}
+ @inputElement = @element.find(".file-finder-input")
+
+ # init event
+ @initEvent()
+
+ # focus text input box
+ @inputElement.focus()
+
+ # load file list
+ @load(@options.url)
+
+ # init event
+ initEvent: ->
+ @inputElement.off "keyup"
+ @inputElement.on "keyup", (event) =>
+ target = $(event.target)
+ value = target.val()
+ oldValue = target.data("oldValue") ? ""
+
+ if value != oldValue
+ target.data("oldValue", value)
+ @findFile()
+ @element.find("tr.tree-item").eq(0).addClass("selected").focus()
+
+ @element.find(".tree-content-holder .tree-table").on "click", (event) ->
+ if (event.target.nodeName != "A")
+ path = @element.find(".tree-item-file-name a", this).attr("href")
+ location.href = path if path
+
+ # find file
+ findFile: ->
+ searchText = @inputElement.val()
+ result = if searchText.length > 0 then fuzzaldrinPlus.filter(@filePaths, searchText) else @filePaths
+ @renderList result, searchText
+
+ # files pathes load
+ load: (url) ->
+ $.ajax
+ url: url
+ method: "get"
+ dataType: "json"
+ success: (data) =>
+ @element.find(".loading").hide()
+ @filePaths = data
+ @findFile()
+ @element.find(".files-slider tr.tree-item").eq(0).addClass("selected").focus()
+
+ # render result
+ renderList: (filePaths, searchText) ->
+ @element.find(".tree-table > tbody").empty()
+
+ for filePath, i in filePaths
+ break if i == 20
+
+ if searchText
+ matches = fuzzaldrinPlus.match(filePath, searchText)
+
+ blobItemUrl = "#{@options.blobUrlTemplate}/#{filePath}"
+
+ html = @makeHtml filePath, matches, blobItemUrl
+ @element.find(".tree-table > tbody").append(html)
+
+ # highlight text(awefwbwgtc -> <b>a</b>wefw<b>b</b>wgt<b>c</b> )
+ highlighter = (element, text, matches) ->
+ lastIndex = 0
+ highlightText = ""
+ matchedChars = []
+
+ for matchIndex in matches
+ unmatched = text.substring(lastIndex, matchIndex)
+
+ if unmatched
+ element.append(matchedChars.join("").bold()) if matchedChars.length
+ matchedChars = []
+ element.append(document.createTextNode(unmatched))
+
+ matchedChars.push(text[matchIndex])
+ lastIndex = matchIndex + 1
+
+ element.append(matchedChars.join("").bold()) if matchedChars.length
+ element.append(document.createTextNode(text.substring(lastIndex)))
+
+ # make tbody row html
+ makeHtml: (filePath, matches, blobItemUrl) ->
+ $tr = $("<tr class='tree-item'><td class='tree-item-file-name'><i class='fa fa-file-text-o fa-fw'></i><span class='str-truncated'><a></a></span></td></tr>")
+ if matches
+ $tr.find("a").replaceWith(highlighter($tr.find("a"), filePath, matches).attr("href", blobItemUrl))
+ else
+ $tr.find("a").attr("href", blobItemUrl).text(filePath)
+
+ return $tr
+
+ selectRow: (type) ->
+ rows = @element.find(".files-slider tr.tree-item")
+ selectedRow = @element.find(".files-slider tr.tree-item.selected")
+
+ if rows && rows.length > 0
+ if selectedRow && selectedRow.length > 0
+ if type == "UP"
+ next = selectedRow.prev()
+ else if type == "DOWN"
+ next = selectedRow.next()
+
+ if next.length > 0
+ selectedRow.removeClass "selected"
+ selectedRow = next
+ else
+ selectedRow = rows.eq(0)
+ selectedRow.addClass("selected").focus()
+
+ selectRowUp: =>
+ @selectRow "UP"
+
+ selectRowDown: =>
+ @selectRow "DOWN"
+
+ goToTree: =>
+ location.href = @options.treeUrl
+
+ goToBlob: =>
+ path = @element.find(".tree-item.selected .tree-item-file-name a").attr("href")
+ location.href = path if path
diff --git a/app/assets/javascripts/shortcuts_find_file.js.coffee b/app/assets/javascripts/shortcuts_find_file.js.coffee
new file mode 100644
index 00000000000..311e80bae19
--- /dev/null
+++ b/app/assets/javascripts/shortcuts_find_file.js.coffee
@@ -0,0 +1,19 @@
+#= require shortcuts_navigation
+
+class @ShortcutsFindFile extends ShortcutsNavigation
+ constructor: (@projectFindFile) ->
+ super()
+ _oldStopCallback = Mousetrap.stopCallback
+ # override to fire shortcuts action when focus in textbox
+ Mousetrap.stopCallback = (event, element, combo) =>
+ if element == @projectFindFile.inputElement[0] and (combo == 'up' or combo == 'down' or combo == 'esc' or combo == 'enter')
+ # when press up/down key in textbox, cusor prevent to move to home/end
+ event.preventDefault()
+ return false
+
+ return _oldStopCallback(event, element, combo)
+
+ Mousetrap.bind('up', @projectFindFile.selectRowUp)
+ Mousetrap.bind('down', @projectFindFile.selectRowDown)
+ Mousetrap.bind('esc', @projectFindFile.goToTree)
+ Mousetrap.bind('enter', @projectFindFile.goToBlob)
diff --git a/app/assets/javascripts/shortcuts_tree.coffee b/app/assets/javascripts/shortcuts_tree.coffee
new file mode 100644
index 00000000000..ba0839c9fc0
--- /dev/null
+++ b/app/assets/javascripts/shortcuts_tree.coffee
@@ -0,0 +1,4 @@
+class @ShortcutsTree extends ShortcutsNavigation
+ constructor: ->
+ super()
+ Mousetrap.bind('t', -> ShortcutsTree.findAndFollowLink('.shortcuts-find-file'))
diff --git a/app/assets/stylesheets/pages/tree.scss b/app/assets/stylesheets/pages/tree.scss
index d4ab6967ccd..97505edeabf 100644
--- a/app/assets/stylesheets/pages/tree.scss
+++ b/app/assets/stylesheets/pages/tree.scss
@@ -1,5 +1,13 @@
.tree-holder {
+ .file-finder {
+ width: 50%;
+ .file-finder-input {
+ width: 95%;
+ display: inline-block;
+ }
+ }
+
.tree-table {
margin-bottom: 0;
diff --git a/app/controllers/projects/find_file_controller.rb b/app/controllers/projects/find_file_controller.rb
new file mode 100644
index 00000000000..54a0c447aee
--- /dev/null
+++ b/app/controllers/projects/find_file_controller.rb
@@ -0,0 +1,26 @@
+# Controller for viewing a repository's file structure
+class Projects::FindFileController < Projects::ApplicationController
+ include ExtractsPath
+ include ActionView::Helpers::SanitizeHelper
+ include TreeHelper
+
+ before_action :require_non_empty_project
+ before_action :assign_ref_vars
+ before_action :authorize_download_code!
+
+ def show
+ return render_404 unless @repository.commit(@ref)
+
+ respond_to do |format|
+ format.html
+ end
+ end
+
+ def list
+ file_paths = @repo.ls_files(@ref)
+
+ respond_to do |format|
+ format.json { render json: file_paths }
+ end
+ end
+end
diff --git a/app/controllers/projects/refs_controller.rb b/app/controllers/projects/refs_controller.rb
index c4e18c17077..a8f091819ca 100644
--- a/app/controllers/projects/refs_controller.rb
+++ b/app/controllers/projects/refs_controller.rb
@@ -20,6 +20,8 @@ class Projects::RefsController < Projects::ApplicationController
namespace_project_network_path(@project.namespace, @project, @id, @options)
when "graphs"
namespace_project_graph_path(@project.namespace, @project, @id)
+ when "find_file"
+ namespace_project_find_file_path(@project.namespace, @project, @id)
when "graphs_commits"
commits_namespace_project_graph_path(@project.namespace, @project, @id)
else
diff --git a/app/models/repository.rb b/app/models/repository.rb
index 6ecd2d2f27e..9deb08d93b8 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -681,6 +681,11 @@ class Repository
end
end
+ def ls_files(ref)
+ actual_ref = ref || root_ref
+ raw_repository.ls_files(actual_ref)
+ end
+
private
def cache
diff --git a/app/views/help/_shortcuts.html.haml b/app/views/help/_shortcuts.html.haml
index e8e331dd109..9ee6f07b26b 100644
--- a/app/views/help/_shortcuts.html.haml
+++ b/app/views/help/_shortcuts.html.haml
@@ -40,6 +40,32 @@
%td.shortcut
.key enter
%td Open Selection
+ %tr
+ %td.shortcut
+ .key t
+ %td Go to finding file
+ %tbody
+ %tr
+ %th
+ %th Finding Project File
+ %tr
+ %td.shortcut
+ .key
+ %i.fa.fa-arrow-up
+ %td Move selection up
+ %tr
+ %td.shortcut
+ .key
+ %i.fa.fa-arrow-down
+ %td Move selection down
+ %tr
+ %td.shortcut
+ .key enter
+ %td Open Selection
+ %tr
+ %td.shortcut
+ .key esc
+ %td Go back
.col-lg-4
%table.shortcut-mappings
diff --git a/app/views/layouts/nav/_project.html.haml b/app/views/layouts/nav/_project.html.haml
index d3eaf0f3209..270ccfd387f 100644
--- a/app/views/layouts/nav/_project.html.haml
+++ b/app/views/layouts/nav/_project.html.haml
@@ -25,7 +25,7 @@
%span
Activity
- if project_nav_tab? :files
- = nav_link(controller: %w(tree blob blame edit_tree new_tree)) do
+ = nav_link(controller: %w(tree blob blame edit_tree new_tree find_file)) do
= link_to project_files_path(@project), title: 'Files', class: 'shortcuts-tree' do
= icon('files-o fw')
%span
@@ -117,4 +117,3 @@
%li.hidden
= link_to namespace_project_network_path(@project.namespace, @project, current_ref), title: 'Network', class: 'shortcuts-network' do
Network
-
diff --git a/app/views/projects/_find_file_link.html.haml b/app/views/projects/_find_file_link.html.haml
new file mode 100644
index 00000000000..08e2fc48be7
--- /dev/null
+++ b/app/views/projects/_find_file_link.html.haml
@@ -0,0 +1,3 @@
+= link_to namespace_project_find_file_path(@project.namespace, @project, @ref), class: 'btn btn-grouped shortcuts-find-file', rel: 'nofollow' do
+ = icon('search')
+ %span Find File
diff --git a/app/views/projects/find_file/show.html.haml b/app/views/projects/find_file/show.html.haml
new file mode 100644
index 00000000000..2930209fb56
--- /dev/null
+++ b/app/views/projects/find_file/show.html.haml
@@ -0,0 +1,27 @@
+- page_title "Find File", @ref
+- header_title project_title(@project, "Files", project_files_path(@project))
+
+.file-finder-holder.tree-holder.clearfix
+ .gray-content-block.top-block
+ .tree-ref-holder
+ = render 'shared/ref_switcher', destination: 'find_file', path: @path
+ %ul.breadcrumb.repo-breadcrumb
+ %li
+ = link_to namespace_project_tree_path(@project.namespace, @project, @ref) do
+ = @project.path
+ %li.file-finder
+ %input#file_find.form-control.file-finder-input{type: "text", placeholder: 'Find by path'}
+
+ %div.tree-content-holder
+ .table-holder
+ %table.table.files-slider{class: "table_#{@hex_path} tree-table table-striped" }
+ %tbody
+ = spinner nil, true
+
+:coffeescript
+ projectFindFile = new ProjectFindFile($(".file-finder-holder"), {
+ url: "#{escape_javascript(namespace_project_files_path(@project.namespace, @project, @ref, @options.merge(format: :json)))}"
+ treeUrl: "#{escape_javascript(namespace_project_tree_path(@project.namespace, @project, @ref))}"
+ blobUrlTemplate: "#{escape_javascript(namespace_project_blob_path(@project.namespace, @project, @id || @commit.id))}"
+ })
+ new ShortcutsFindFile(projectFindFile)
diff --git a/app/views/projects/tree/show.html.haml b/app/views/projects/tree/show.html.haml
index ec14bd7f65a..c57570afa09 100644
--- a/app/views/projects/tree/show.html.haml
+++ b/app/views/projects/tree/show.html.haml
@@ -3,12 +3,12 @@
= content_for :meta_tags do
- if current_user
= auto_discovery_link_tag(:atom, namespace_project_commits_url(@project.namespace, @project, @ref, format: :atom, private_token: current_user.private_token), title: "#{@project.name}:#{@ref} commits")
-
= render 'projects/last_push'
-- if can? current_user, :download_code, @project
- .tree-download-holder
- = render 'projects/repositories/download_archive', ref: @ref, btn_class: 'btn-group pull-right hidden-xs hidden-sm', split_button: true
+.pull-right
+ = render 'projects/find_file_link'
+ - if can? current_user, :download_code, @project
+ = render 'projects/repositories/download_archive', ref: @ref, btn_class: 'hidden-xs hidden-sm btn-grouped', split_button: true
#tree-holder.tree-holder.clearfix
.gray-content-block.top-block