Skip to content

Commit c10a6f2

Browse files
tancnlebethesque
authored andcommitted
feat: add copy to clipboard for version numbers (pact-foundation#283)
* Add Copy to clipboard button for consumer and provider version * Move clipboard functionalities to a separate file. * Add Copy to clipboard to matrix page. * Add visual cue that the text has been copied * Remove violated CSS rules * Initialize copy-to-clipboard functionality with explicit selector * Rename bootstrap method to reveal better intent.
1 parent e5b5f8f commit c10a6f2

File tree

6 files changed

+113
-6
lines changed

6 files changed

+113
-6
lines changed

lib/pact_broker/ui/views/index/_css_and_js.haml

+1
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@
55
%script{type: 'text/javascript', src:'/javascripts/jquery.tablesorter.min.js'}
66
%script{type: 'text/javascript', src:'/javascripts/material-menu.js'}
77
%script{type: 'text/javascript', src:'/javascripts/index.js'}
8+
%script{type: 'text/javascript', src:'/javascripts/clipboard.js'}
89
%script{type: 'text/javascript', src:'/javascripts/jquery-confirm.min.js'}

lib/pact_broker/ui/views/index/show-with-tags.haml

+8-2
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,10 @@
3939
%a{:href => index_item.consumer_group_url }
4040
= escape_html(index_item.consumer_name)
4141
%td.consumer-version-number
42-
%div
42+
%div.clippable
4343
= escape_html(index_item.consumer_version_number)
44+
%button.clippy.hidden{ title: "Copy to clipboard" }
45+
%span.glyphicon.glyphicon-copy
4446
- if index_item.latest?
4547
.tag.label.label-success
4648
latest
@@ -56,8 +58,10 @@
5658
%a{ href: index_item.provider_group_url }
5759
= escape_html(index_item.provider_name)
5860
%td.provider-version-number
59-
%div
61+
%div.clippable
6062
= escape_html(index_item.provider_version_number)
63+
%button.clippy.hidden{ title: "Copy to clipboard" }
64+
%span.glyphicon.glyphicon-copy
6165
- index_item.provider_version_latest_tag_names.each do | tag_name |
6266
.tag.label.label-primary
6367
= escape_html(tag_name)
@@ -85,6 +89,8 @@
8589
});
8690

8791
$(document).ready(function(){
92+
initializeClipper(".clippable");
93+
8894
$("span.pact a").load("/images/doc-text.svg");
8995
$("span.pact-matrix a").load("/images/doc-matrix.svg");
9096
$('td[data-toggle="tooltip"]').each(function(index, td){

lib/pact_broker/ui/views/matrix/show.haml

+12-2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
%script{type: 'text/javascript', src:'/javascripts/jquery-3.3.1.min.js'}
66
%script{type: 'text/javascript', src:'/javascripts/jquery.tablesorter.min.js'}
77
%script{type: 'text/javascript', src:'/javascripts/matrix.js'}
8+
%script{type: 'text/javascript', src:'/javascripts/clipboard.js'}
89
%script{type: 'text/javascript', src:'/js/bootstrap.min.js'}
910

1011
.container
@@ -102,9 +103,11 @@
102103
%a{href: line.consumer_name_url}
103104
= line.consumer_name
104105
%td.consumer-version{'data-sort-value' => line.consumer_version_order}
105-
%div
106+
%div.clippable
106107
%a{href: line.consumer_version_number_url}
107108
= line.display_consumer_version_number
109+
%button.clippy.hidden{ title: "Copy to clipboard" }
110+
%span.glyphicon.glyphicon-copy
108111
- line.latest_consumer_version_tags.each do | tag |
109112
.tag-parent{"title": tag.tooltip, "data-toggle": "tooltip", "data-placement": "right"}
110113
%a{href: tag.url}
@@ -126,9 +129,11 @@
126129
%a{href: line.provider_name_url}
127130
= line.provider_name
128131
%td.provider-version{'data-sort-value' => line.provider_version_order}
129-
%div
132+
%div.clippable
130133
%a{href: line.provider_version_number_url}
131134
= line.display_provider_version_number
135+
%button.clippy.hidden{ title: "Copy to clipboard" }
136+
%span.glyphicon.glyphicon-copy
132137
- line.latest_provider_version_tags.each do | tag |
133138
.tag-parent{"title": tag.tooltip, "data-toggle": "tooltip", "data-placement": "right"}
134139
%a{href: tag.url}
@@ -145,3 +150,8 @@
145150
= "#{line.verification_status} (number #{line.number})"
146151
- else
147152
= line.verification_status
153+
154+
:javascript
155+
$(document).ready(function(){
156+
initializeClipper(".clippable");
157+
});

public/javascripts/clipboard.js

+73
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/**
2+
* Include code to enable copy-to-clipboard functionality
3+
* and currently used on index and matrix tables
4+
* @example in Haml
5+
* %div.clippable
6+
* = Text to be copied
7+
* %button.clippy.hidden{ title: "Copy to clipboard" }
8+
* %span.glyphicon.glyphicon-copy
9+
*/
10+
11+
/**
12+
* Bootstrap copy-to-clipboard functionality
13+
* @param {string} selector CSS selector of elements that require
14+
* copy-to-clipboard functionality
15+
*/
16+
function initializeClipper(selector) {
17+
const elements = $(selector);
18+
19+
elements.hover(function() {
20+
$(this).children(".clippy").toggleClass("hidden");
21+
});
22+
23+
elements
24+
.children(".clippy")
25+
.click(function() {
26+
const clippyButton = $(this);
27+
const text = $.trim(clippyButton.closest(selector).text());
28+
29+
copyToClipboard(text);
30+
flashClipped(clippyButton);
31+
});
32+
}
33+
34+
/**
35+
* Copy text to clipboard using execCommand
36+
* @see https://gist.github.com/Chalarangelo/4ff1e8c0ec03d9294628efbae49216db#file-copytoclipboard-js
37+
* @see https://developer.mozilla.org/en-US/docs/Web/API/Document/execCommand
38+
* @param {string} text text to be copied to clipboard
39+
*/
40+
function copyToClipboard(text) {
41+
const el = document.createElement('textarea');
42+
el.value = text;
43+
el.setAttribute('readonly', '');
44+
el.style.position = 'absolute';
45+
el.style.left = '-9999px';
46+
document.body.appendChild(el);
47+
48+
const selected =
49+
document.getSelection().rangeCount > 0
50+
? document.getSelection().getRangeAt(0)
51+
: false;
52+
el.select();
53+
document.execCommand('copy');
54+
document.body.removeChild(el);
55+
if (selected) {
56+
document.getSelection().removeAllRanges();
57+
document.getSelection().addRange(selected);
58+
}
59+
}
60+
61+
/**
62+
* Flash a success tick to indicate successful copy-to-clipboard action
63+
* @param {jQuery Element} clipButton button to copy to clipboard
64+
*/
65+
function flashClipped(clippyButton) {
66+
const icon = clippyButton.children("span");
67+
icon.attr("class", "glyphicon glyphicon-ok success");
68+
69+
setTimeout(
70+
function() { icon.attr("class", "glyphicon glyphicon-copy"); },
71+
2000
72+
);
73+
}

public/javascripts/matrix.js

-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
function setTextboxVisibility(selectBox, cssSelector, visibility) {
32
var textbox = selectBox.closest('.selector').find(cssSelector);
43
textbox.toggle(visibility);
@@ -65,7 +64,6 @@ $(document).ready(function(){
6564
}
6665
});
6766

68-
6967
$('[data-toggle="tooltip"]').each(function(index, el){
7068
$(el).tooltip({container: $(el)});
7169
});

public/stylesheets/index.css

+19
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,25 @@ body { padding-top: 10px; }
5656
word-wrap: break-word;
5757
}
5858

59+
.clippable {
60+
display: flex;
61+
justify-content: flex-start;
62+
}
63+
64+
.clippy {
65+
padding: 0 4px;
66+
border: none;
67+
background: none;
68+
}
69+
70+
.clippy:hover {
71+
color: #2a6496;
72+
}
73+
74+
.success {
75+
color: #5cb85c
76+
}
77+
5978
span.pact {
6079
display: inline-block;
6180
}

0 commit comments

Comments
 (0)