Copy diff file path as GFM

This commit is contained in:
Douwe Maan 2017-04-06 21:10:14 +00:00 committed by Robert Speicher
parent 00e00cacf8
commit 12c18ee546
20 changed files with 88 additions and 39 deletions

View file

@ -38,9 +38,35 @@ showTooltip = function(target, title) {
}; };
$(function() { $(function() {
var clipboard; const clipboard = new Clipboard('[data-clipboard-target], [data-clipboard-text]');
clipboard = new Clipboard('[data-clipboard-target], [data-clipboard-text]');
clipboard.on('success', genericSuccess); clipboard.on('success', genericSuccess);
return clipboard.on('error', genericError); clipboard.on('error', genericError);
// This a workaround around ClipboardJS limitations to allow the context-specific copy/pasting of plain text or GFM.
// The Ruby `clipboard_button` helper sneaks a JSON hash with `text` and `gfm` keys into the `data-clipboard-text`
// attribute that ClipboardJS reads from.
// When ClipboardJS creates a new `textarea` (directly inside `body`, with a `readonly` attribute`), sets its value
// to the value of this data attribute, focusses on it, and finally programmatically issues the 'Copy' command,
// this code intercepts the copy command/event at the last minute to deconstruct this JSON hash and set the
// `text/plain` and `text/x-gfm` copy data types to the intended values.
$(document).on('copy', 'body > textarea[readonly]', function(e) {
const clipboardData = e.originalEvent.clipboardData;
if (!clipboardData) return;
const text = e.target.value;
let json;
try {
json = JSON.parse(text);
} catch (ex) {
return;
}
if (!json.text || !json.gfm) return;
e.preventDefault();
clipboardData.setData('text/plain', json.text);
clipboardData.setData('text/x-gfm', json.gfm);
});
}); });

View file

@ -210,13 +210,13 @@ module BlobHelper
end end
def copy_file_path_button(file_path) def copy_file_path_button(file_path)
clipboard_button(clipboard_text: file_path, class: 'btn-clipboard btn-transparent prepend-left-5', title: 'Copy file path to clipboard') clipboard_button(text: file_path, gfm: "`#{file_path}`", class: 'btn-clipboard btn-transparent prepend-left-5', title: 'Copy file path to clipboard')
end end
def copy_blob_content_button(blob) def copy_blob_content_button(blob)
return if markup?(blob.name) return if markup?(blob.name)
clipboard_button(clipboard_target: ".blob-content[data-blob-id='#{blob.id}']", class: "btn btn-sm", title: "Copy content to clipboard") clipboard_button(target: ".blob-content[data-blob-id='#{blob.id}']", class: "btn btn-sm", title: "Copy content to clipboard")
end end
def open_raw_file_button(path) def open_raw_file_button(path)

View file

@ -1,23 +1,42 @@
module ButtonHelper module ButtonHelper
# Output a "Copy to Clipboard" button # Output a "Copy to Clipboard" button
# #
# data - Data attributes passed to `content_tag` # data - Data attributes passed to `content_tag` (default: {}):
# :text - Text to copy (optional)
# :gfm - GitLab Flavored Markdown to copy, if different from `text` (optional)
# :target - Selector for target element to copy from (optional)
# #
# Examples: # Examples:
# #
# # Define the clipboard's text # # Define the clipboard's text
# clipboard_button(clipboard_text: "Foo") # clipboard_button(text: "Foo")
# # => "<button class='...' data-clipboard-text='Foo'>...</button>" # # => "<button class='...' data-clipboard-text='Foo'>...</button>"
# #
# # Define the target element # # Define the target element
# clipboard_button(clipboard_target: "div#foo") # clipboard_button(target: "div#foo")
# # => "<button class='...' data-clipboard-target='div#foo'>...</button>" # # => "<button class='...' data-clipboard-target='div#foo'>...</button>"
# #
# See http://clipboardjs.com/#usage # See http://clipboardjs.com/#usage
def clipboard_button(data = {}) def clipboard_button(data = {})
css_class = data[:class] || 'btn-clipboard btn-transparent' css_class = data[:class] || 'btn-clipboard btn-transparent'
title = data[:title] || 'Copy to clipboard' title = data[:title] || 'Copy to clipboard'
# This supports code in app/assets/javascripts/copy_to_clipboard.js that
# works around ClipboardJS limitations to allow the context-specific copy/pasting of plain text or GFM.
if text = data.delete(:text)
data[:clipboard_text] =
if gfm = data.delete(:gfm)
{ text: text, gfm: gfm }
else
text
end
end
target = data.delete(:target)
data[:clipboard_target] = target if target
data = { toggle: 'tooltip', placement: 'bottom', container: 'body' }.merge(data) data = { toggle: 'tooltip', placement: 'bottom', container: 'body' }.merge(data)
content_tag :button, content_tag :button,
icon('clipboard', 'aria-hidden': 'true'), icon('clipboard', 'aria-hidden': 'true'),
class: "btn #{css_class}", class: "btn #{css_class}",

View file

@ -19,7 +19,7 @@
Your New Personal Access Token Your New Personal Access Token
.form-group .form-group
= text_field_tag 'created-personal-access-token', flash[:personal_access_token], readonly: true, class: "form-control", 'aria-describedby' => "created-personal-access-token-help-block" = text_field_tag 'created-personal-access-token', flash[:personal_access_token], readonly: true, class: "form-control", 'aria-describedby' => "created-personal-access-token-help-block"
= clipboard_button(clipboard_text: flash[:personal_access_token], title: "Copy personal access token to clipboard", placement: "left") = clipboard_button(text: flash[:personal_access_token], title: "Copy personal access token to clipboard", placement: "left")
%span#created-personal-access-token-help-block.help-block.text-danger Make sure you save it - you won't be able to access it again. %span#created-personal-access-token-help-block.help-block.text-danger Make sure you save it - you won't be able to access it again.
%hr %hr

View file

@ -10,7 +10,7 @@
- if @project && event.project != @project - if @project && event.project != @project
%span at %span at
%strong= link_to_project event.project %strong= link_to_project event.project
= clipboard_button(clipboard_text: event.ref_name, class: 'btn-clipboard btn-transparent', title: 'Copy branch to clipboard') = clipboard_button(text: event.ref_name, class: 'btn-clipboard btn-transparent', title: 'Copy branch to clipboard')
#{time_ago_with_tooltip(event.created_at)} #{time_ago_with_tooltip(event.created_at)}
.pull-right .pull-right

View file

@ -1,7 +1,7 @@
.page-content-header .page-content-header
.header-main-content .header-main-content
%strong Commit #{@commit.short_id} %strong Commit #{@commit.short_id}
= clipboard_button(clipboard_text: @commit.id, title: "Copy commit SHA to clipboard") = clipboard_button(text: @commit.id, title: "Copy commit SHA to clipboard")
%span.hidden-xs authored %span.hidden-xs authored
#{time_ago_with_tooltip(@commit.authored_date)} #{time_ago_with_tooltip(@commit.authored_date)}
%span by %span by

View file

@ -37,6 +37,6 @@
.commit-actions.flex-row.hidden-xs .commit-actions.flex-row.hidden-xs
- if commit.status(ref) - if commit.status(ref)
= render_commit_status(commit, ref: ref) = render_commit_status(commit, ref: ref)
= clipboard_button(clipboard_text: commit.id, title: "Copy commit SHA to clipboard") = clipboard_button(text: commit.id, title: "Copy commit SHA to clipboard")
= link_to commit.short_id, namespace_project_commit_path(project.namespace, project, commit), class: "commit-short-id btn btn-transparent" = link_to commit.short_id, namespace_project_commit_path(project.namespace, project, commit), class: "commit-short-id btn btn-transparent"
= link_to_browse_code(project, commit) = link_to_browse_code(project, commit)

View file

@ -16,7 +16,7 @@
.email-modal-input-group.input-group .email-modal-input-group.input-group
= text_field_tag :issue_email, email, class: "monospace js-select-on-focus form-control", readonly: true = text_field_tag :issue_email, email, class: "monospace js-select-on-focus form-control", readonly: true
.input-group-btn .input-group-btn
= clipboard_button(clipboard_target: '#issue_email') = clipboard_button(target: '#issue_email')
%p %p
The subject will be used as the title of the new issue, and the message will be the description. The subject will be used as the title of the new issue, and the message will be the description.

View file

@ -8,7 +8,7 @@
%p %p
%strong Step 1. %strong Step 1.
Fetch and check out the branch for this merge request Fetch and check out the branch for this merge request
= clipboard_button(clipboard_target: "pre#merge-info-1", title: "Copy commands to clipboard") = clipboard_button(target: "pre#merge-info-1", title: "Copy commands to clipboard")
%pre.dark#merge-info-1 %pre.dark#merge-info-1
- if @merge_request.for_fork? - if @merge_request.for_fork?
:preserve :preserve
@ -25,7 +25,7 @@
%p %p
%strong Step 3. %strong Step 3.
Merge the branch and fix any conflicts that come up Merge the branch and fix any conflicts that come up
= clipboard_button(clipboard_target: "pre#merge-info-3", title: "Copy commands to clipboard") = clipboard_button(target: "pre#merge-info-3", title: "Copy commands to clipboard")
%pre.dark#merge-info-3 %pre.dark#merge-info-3
- if @merge_request.for_fork? - if @merge_request.for_fork?
:preserve :preserve
@ -38,7 +38,7 @@
%p %p
%strong Step 4. %strong Step 4.
Push the result of the merge to GitLab Push the result of the merge to GitLab
= clipboard_button(clipboard_target: "pre#merge-info-4", title: "Copy commands to clipboard") = clipboard_button(target: "pre#merge-info-4", title: "Copy commands to clipboard")
%pre.dark#merge-info-4 %pre.dark#merge-info-4
:preserve :preserve
git push origin #{h @merge_request.target_branch} git push origin #{h @merge_request.target_branch}

View file

@ -46,4 +46,4 @@
\... \...
%span.js-details-content.hide %span.js-details-content.hide
= link_to @pipeline.sha, namespace_project_commit_path(@project.namespace, @project, @pipeline.sha), class: "monospace commit-hash-full" = link_to @pipeline.sha, namespace_project_commit_path(@project.namespace, @project, @pipeline.sha), class: "monospace commit-hash-full"
= clipboard_button(clipboard_text: @pipeline.sha, title: "Copy commit SHA to clipboard") = clipboard_button(text: @pipeline.sha, title: "Copy commit SHA to clipboard")

View file

@ -1,7 +1,7 @@
%tr.tag %tr.tag
%td %td
= escape_once(tag.name) = escape_once(tag.name)
= clipboard_button(clipboard_text: "docker pull #{tag.path}") = clipboard_button(text: "docker pull #{tag.path}")
%td %td
- if tag.revision - if tag.revision
%span.has-tooltip{ title: "#{tag.revision}" } %span.has-tooltip{ title: "#{tag.revision}" }

View file

@ -22,14 +22,14 @@
.col-sm-10.col-xs-12.input-group .col-sm-10.col-xs-12.input-group
= text_field_tag :display_name, "GitLab / #{@project.name_with_namespace}", class: 'form-control input-sm', readonly: 'readonly' = text_field_tag :display_name, "GitLab / #{@project.name_with_namespace}", class: 'form-control input-sm', readonly: 'readonly'
.input-group-btn .input-group-btn
= clipboard_button(clipboard_target: '#display_name') = clipboard_button(target: '#display_name')
.form-group .form-group
= label_tag :description, 'Description', class: 'col-sm-2 col-xs-12 control-label' = label_tag :description, 'Description', class: 'col-sm-2 col-xs-12 control-label'
.col-sm-10.col-xs-12.input-group .col-sm-10.col-xs-12.input-group
= text_field_tag :description, run_actions_text, class: 'form-control input-sm', readonly: 'readonly' = text_field_tag :description, run_actions_text, class: 'form-control input-sm', readonly: 'readonly'
.input-group-btn .input-group-btn
= clipboard_button(clipboard_target: '#description') = clipboard_button(target: '#description')
.form-group .form-group
= label_tag nil, 'Command trigger word', class: 'col-sm-2 col-xs-12 control-label' = label_tag nil, 'Command trigger word', class: 'col-sm-2 col-xs-12 control-label'
@ -46,7 +46,7 @@
.col-sm-10.col-xs-12.input-group .col-sm-10.col-xs-12.input-group
= text_field_tag :request_url, service_trigger_url(subject), class: 'form-control input-sm', readonly: 'readonly' = text_field_tag :request_url, service_trigger_url(subject), class: 'form-control input-sm', readonly: 'readonly'
.input-group-btn .input-group-btn
= clipboard_button(clipboard_target: '#request_url') = clipboard_button(target: '#request_url')
.form-group .form-group
= label_tag nil, 'Request method', class: 'col-sm-2 col-xs-12 control-label' = label_tag nil, 'Request method', class: 'col-sm-2 col-xs-12 control-label'
@ -57,14 +57,14 @@
.col-sm-10.col-xs-12.input-group .col-sm-10.col-xs-12.input-group
= text_field_tag :response_username, 'GitLab', class: 'form-control input-sm', readonly: 'readonly' = text_field_tag :response_username, 'GitLab', class: 'form-control input-sm', readonly: 'readonly'
.input-group-btn .input-group-btn
= clipboard_button(clipboard_target: '#response_username') = clipboard_button(target: '#response_username')
.form-group .form-group
= label_tag :response_icon, 'Response icon', class: 'col-sm-2 col-xs-12 control-label' = label_tag :response_icon, 'Response icon', class: 'col-sm-2 col-xs-12 control-label'
.col-sm-10.col-xs-12.input-group .col-sm-10.col-xs-12.input-group
= text_field_tag :response_icon, asset_url('gitlab_logo.png'), class: 'form-control input-sm', readonly: 'readonly' = text_field_tag :response_icon, asset_url('gitlab_logo.png'), class: 'form-control input-sm', readonly: 'readonly'
.input-group-btn .input-group-btn
= clipboard_button(clipboard_target: '#response_icon') = clipboard_button(target: '#response_icon')
.form-group .form-group
= label_tag nil, 'Autocomplete', class: 'col-sm-2 col-xs-12 control-label' = label_tag nil, 'Autocomplete', class: 'col-sm-2 col-xs-12 control-label'
@ -75,14 +75,14 @@
.col-sm-10.col-xs-12.input-group .col-sm-10.col-xs-12.input-group
= text_field_tag :autocomplete_hint, '[help]', class: 'form-control input-sm', readonly: 'readonly' = text_field_tag :autocomplete_hint, '[help]', class: 'form-control input-sm', readonly: 'readonly'
.input-group-btn .input-group-btn
= clipboard_button(clipboard_target: '#autocomplete_hint') = clipboard_button(target: '#autocomplete_hint')
.form-group .form-group
= label_tag :autocomplete_description, 'Autocomplete description', class: 'col-sm-2 col-xs-12 control-label' = label_tag :autocomplete_description, 'Autocomplete description', class: 'col-sm-2 col-xs-12 control-label'
.col-sm-10.col-xs-12.input-group .col-sm-10.col-xs-12.input-group
= text_field_tag :autocomplete_description, run_actions_text, class: 'form-control input-sm', readonly: 'readonly' = text_field_tag :autocomplete_description, run_actions_text, class: 'form-control input-sm', readonly: 'readonly'
.input-group-btn .input-group-btn
= clipboard_button(clipboard_target: '#autocomplete_description') = clipboard_button(target: '#autocomplete_description')
%hr %hr

View file

@ -40,7 +40,7 @@
.col-sm-10.col-xs-12.input-group .col-sm-10.col-xs-12.input-group
= text_field_tag :url, service_trigger_url(subject), class: 'form-control input-sm', readonly: 'readonly' = text_field_tag :url, service_trigger_url(subject), class: 'form-control input-sm', readonly: 'readonly'
.input-group-btn .input-group-btn
= clipboard_button(clipboard_target: '#url') = clipboard_button(target: '#url')
.form-group .form-group
= label_tag nil, 'Method', class: 'col-sm-2 col-xs-12 control-label' = label_tag nil, 'Method', class: 'col-sm-2 col-xs-12 control-label'
@ -51,7 +51,7 @@
.col-sm-10.col-xs-12.input-group .col-sm-10.col-xs-12.input-group
= text_field_tag :customize_name, 'GitLab', class: 'form-control input-sm', readonly: 'readonly' = text_field_tag :customize_name, 'GitLab', class: 'form-control input-sm', readonly: 'readonly'
.input-group-btn .input-group-btn
= clipboard_button(clipboard_target: '#customize_name') = clipboard_button(target: '#customize_name')
.form-group .form-group
= label_tag nil, 'Customize icon', class: 'col-sm-2 col-xs-12 control-label' = label_tag nil, 'Customize icon', class: 'col-sm-2 col-xs-12 control-label'
@ -68,21 +68,21 @@
.col-sm-10.col-xs-12.input-group .col-sm-10.col-xs-12.input-group
= text_field_tag :autocomplete_description, run_actions_text, class: 'form-control input-sm', readonly: 'readonly' = text_field_tag :autocomplete_description, run_actions_text, class: 'form-control input-sm', readonly: 'readonly'
.input-group-btn .input-group-btn
= clipboard_button(clipboard_target: '#autocomplete_description') = clipboard_button(target: '#autocomplete_description')
.form-group .form-group
= label_tag :autocomplete_usage_hint, 'Autocomplete usage hint', class: 'col-sm-2 col-xs-12 control-label' = label_tag :autocomplete_usage_hint, 'Autocomplete usage hint', class: 'col-sm-2 col-xs-12 control-label'
.col-sm-10.col-xs-12.input-group .col-sm-10.col-xs-12.input-group
= text_field_tag :autocomplete_usage_hint, '[help]', class: 'form-control input-sm', readonly: 'readonly' = text_field_tag :autocomplete_usage_hint, '[help]', class: 'form-control input-sm', readonly: 'readonly'
.input-group-btn .input-group-btn
= clipboard_button(clipboard_target: '#autocomplete_usage_hint') = clipboard_button(target: '#autocomplete_usage_hint')
.form-group .form-group
= label_tag :descriptive_label, 'Descriptive label', class: 'col-sm-2 col-xs-12 control-label' = label_tag :descriptive_label, 'Descriptive label', class: 'col-sm-2 col-xs-12 control-label'
.col-sm-10.col-xs-12.input-group .col-sm-10.col-xs-12.input-group
= text_field_tag :descriptive_label, 'Perform common operations on GitLab project', class: 'form-control input-sm', readonly: 'readonly' = text_field_tag :descriptive_label, 'Perform common operations on GitLab project', class: 'form-control input-sm', readonly: 'readonly'
.input-group-btn .input-group-btn
= clipboard_button(clipboard_target: '#descriptive_label') = clipboard_button(target: '#descriptive_label')
%hr %hr

View file

@ -10,7 +10,7 @@
%i.fa.fa-angle-right %i.fa.fa-angle-right
%small.light %small.light
= link_to @commit.short_id, namespace_project_commit_path(@project.namespace, @project, @commit), class: "monospace" = link_to @commit.short_id, namespace_project_commit_path(@project.namespace, @project, @commit), class: "monospace"
= clipboard_button(clipboard_text: @commit.id, title: "Copy commit SHA to clipboard") = clipboard_button(text: @commit.id, title: "Copy commit SHA to clipboard")
= time_ago_with_tooltip(@commit.committed_date) = time_ago_with_tooltip(@commit.committed_date)
\- \-
= @commit.full_title = @commit.full_title

View file

@ -2,7 +2,7 @@
%td %td
- if can?(current_user, :admin_trigger, trigger) - if can?(current_user, :admin_trigger, trigger)
%span= trigger.token %span= trigger.token
= clipboard_button(clipboard_text: trigger.token, title: "Copy trigger token to clipboard") = clipboard_button(text: trigger.token, title: "Copy trigger token to clipboard")
- else - else
%span= trigger.short_token %span= trigger.short_token

View file

@ -19,7 +19,7 @@
= text_field_tag :project_clone, default_url_to_repo(project), class: "js-select-on-focus form-control", readonly: true = text_field_tag :project_clone, default_url_to_repo(project), class: "js-select-on-focus form-control", readonly: true
.input-group-btn .input-group-btn
= clipboard_button(clipboard_target: '#project_clone', title: "Copy URL to clipboard") = clipboard_button(target: '#project_clone', title: "Copy URL to clipboard")
:javascript :javascript
$('ul.clone-options-dropdown a').on('click',function(e){ $('ul.clone-options-dropdown a').on('click',function(e){

View file

@ -33,7 +33,7 @@
- if impersonation - if impersonation
%td.token-token-container %td.token-token-container
= text_field_tag 'impersonation-token-token', token.token, readonly: true, class: "form-control" = text_field_tag 'impersonation-token-token', token.token, readonly: true, class: "form-control"
= clipboard_button(clipboard_text: token.token) = clipboard_button(text: token.token)
- path = impersonation ? revoke_admin_user_impersonation_token_path(token.user, token) : revoke_profile_personal_access_token_path(token) - path = impersonation ? revoke_admin_user_impersonation_token_path(token.user, token) : revoke_profile_personal_access_token_path(token)
%td= link_to "Revoke", path, method: :put, class: "btn btn-danger pull-right", data: { confirm: "Are you sure you want to revoke this #{type} Token? This action cannot be undone." } %td= link_to "Revoke", path, method: :put, class: "btn btn-danger pull-right", data: { confirm: "Are you sure you want to revoke this #{type} Token? This action cannot be undone." }
- else - else

View file

@ -160,13 +160,13 @@
- project_ref = cross_project_reference(@project, issuable) - project_ref = cross_project_reference(@project, issuable)
.block.project-reference .block.project-reference
.sidebar-collapsed-icon.dont-change-state .sidebar-collapsed-icon.dont-change-state
= clipboard_button(clipboard_text: project_ref, title: "Copy reference to clipboard", placement: "left") = clipboard_button(text: project_ref, title: "Copy reference to clipboard", placement: "left")
.cross-project-reference.hide-collapsed .cross-project-reference.hide-collapsed
%span %span
Reference: Reference:
%cite{ title: project_ref } %cite{ title: project_ref }
= project_ref = project_ref
= clipboard_button(clipboard_text: project_ref, title: "Copy reference to clipboard", placement: "left") = clipboard_button(text: project_ref, title: "Copy reference to clipboard", placement: "left")
:javascript :javascript
gl.IssuableResource = new gl.SubbableResource('#{issuable_json_path(issuable)}'); gl.IssuableResource = new gl.SubbableResource('#{issuable_json_path(issuable)}');

View file

@ -122,10 +122,10 @@
- if milestone_ref.present? - if milestone_ref.present?
.block.reference .block.reference
.sidebar-collapsed-icon.dont-change-state .sidebar-collapsed-icon.dont-change-state
= clipboard_button(clipboard_text: milestone_ref, title: "Copy reference to clipboard", placement: "left") = clipboard_button(text: milestone_ref, title: "Copy reference to clipboard", placement: "left")
.cross-project-reference.hide-collapsed .cross-project-reference.hide-collapsed
%span %span
Reference: Reference:
%cite{ title: milestone_ref } %cite{ title: milestone_ref }
= milestone_ref = milestone_ref
= clipboard_button(clipboard_text: milestone_ref, title: "Copy reference to clipboard", placement: "left") = clipboard_button(text: milestone_ref, title: "Copy reference to clipboard", placement: "left")

View file

@ -0,0 +1,4 @@
---
title: After copying a diff file or blob path, pasting it into a comment field will format it as Markdown.
merge_request: 9876
author: