diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 45ce68988..5fab60914 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -1817,6 +1817,16 @@ module ApplicationHelper
)
end
+ def copy_object_url_link(url, only_icon=false)
+ tag.div(class: 'copy-link-wrapper') do
+ link_to_function(l(:button_copy_link), "copyTextToClipboard(this);",
+ class: "#{only_icon ? 'icon-only' : 'icon'} icon-copy-link",
+ data: {'clipboard-text' => url},
+ title: l(:button_copy_link)) +
+ tag.span(l(:text_success_copied), class: 'success-copied-message')
+ end
+ end
+
private
def wiki_helper
diff --git a/app/helpers/journals_helper.rb b/app/helpers/journals_helper.rb
index d947f8233..2f2322645 100644
--- a/app/helpers/journals_helper.rb
+++ b/app/helpers/journals_helper.rb
@@ -28,9 +28,11 @@ module JournalsHelper
# Returns the action links for an issue journal
def render_journal_actions(issue, journal, options={})
links = []
+ indice = journal.indice || @journal.issue.visible_journals_with_index.find{|j| j.id == @journal.id}.indice
+
+ links << copy_object_url_link(issue_url(issue, anchor: "note-#{indice}", only_path: false), true)
if journal.notes.present?
if options[:reply_links]
- indice = journal.indice || @journal.issue.visible_journals_with_index.find{|j| j.id == @journal.id}.indice
links << link_to(l(:button_quote),
quoted_issue_path(issue, :journal_id => journal, :journal_indice => indice),
:remote => true,
diff --git a/app/views/issues/_action_menu.html.erb b/app/views/issues/_action_menu.html.erb
index bd7bcc05f..438e9df31 100644
--- a/app/views/issues/_action_menu.html.erb
+++ b/app/views/issues/_action_menu.html.erb
@@ -4,6 +4,7 @@
:class => 'icon icon-edit', :accesskey => accesskey(:edit) if @issue.editable? %>
<%= link_to l(:button_log_time), new_issue_time_entry_path(@issue),
:class => 'icon icon-time-add' if User.current.allowed_to?(:log_time, @project) %>
+<%= copy_object_url_link(issue_url(@issue, only_path: false)) %>
<%= watcher_link(@issue, User.current) %>
<%= link_to l(:button_copy), project_copy_issue_path(@project, @issue),
:class => 'icon icon-copy' if User.current.allowed_to?(:copy_issues, @project) && Issue.allowed_target_projects.any? %>
diff --git a/config/locales/en.yml b/config/locales/en.yml
index 00f246f33..33dee1470 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -1145,6 +1145,7 @@ en:
button_change_password: Change password
button_copy: Copy
button_copy_and_follow: Copy and follow
+ button_copy_link: Copy link
button_annotate: Annotate
button_update: Update
button_configure: Configure
@@ -1263,6 +1264,7 @@ en:
text_select_apply_tracker: "Select tracker"
text_avatar_server_config_html: The current avatar server is %{url}. You can configure it in config/configuration.yml.
text_no_subject: no subject
+ text_success_copied: Copied.
default_role_manager: Manager
diff --git a/public/images/page_link.png b/public/images/page_link.png
new file mode 100644
index 0000000000000000000000000000000000000000..312eab0914ab59271384686255d1be913a6b3add
GIT binary patch
literal 830
zcmV-E1Ht@>P)VWgGzD=Y79#JI$lhEn`|2MpRa?Bt#-nSD~P0P(mbVe{KrOBoKnSsk>m|ML{6l
zBosu@om4j#WzNLRAk+{k1JRvL(MfE&vvbb->v>W{*z*1_uMP}0cIRX*?mz+wk%*#O
z%0D-+$B*g1nRkvI+_3E8Pr1NC6@5M&4vWaLCnNlr;lNlr4i91z&)eBGqL{L{GNu;Fof}GS9{gM5BJuH;2QWk8yuOZdB3pGR#s8bd~
zAmt<>3Q=YH$t5YJ5;7@+8Uh6=ktBgY6#6Pa%2F?h910?U8cLT43KAj$Z1*==ra&gILO{WkHfs(--F=bly9l~${z@AT>V$oat!YAD@M
zBE0v_F{`g#^wOSP-u~!wvlmXdd*uqFqoZ0^{&nEMDU+=!>({S0wrQhFmoB}Yq1)~0
z^{A)L8Xjzdr(W4_exYO6u3a{4*kIeXZMJUR>Q=ksjW_p!rAwDKYUs90>6Q|C>56o@
zbrSq^Xk7Gq#>dAsn@un`Hz$?w$;Ss`%jV7L%9ShgHFV~C)6M>B`Tp%|nqPc&G*A3|
z)Qe+}vT4-x^t1~XE@(6wR;^lPWMo9n*~E!cy~)YRsT2{`?fqeIw-e7N@mOA%UcCIq
z_kH(_EK7|>pM*1Wt2^DaDAp|cvp*@(ZZDKpYkKC^?97(`0sb&XTXy7N#sB~S07*qo
IM6N<$f;YmCWB>pF
literal 0
HcmV?d00001
diff --git a/public/javascripts/application.js b/public/javascripts/application.js
index feabd9ca9..ca582a35b 100644
--- a/public/javascripts/application.js
+++ b/public/javascripts/application.js
@@ -563,6 +563,22 @@ function randomKey(size) {
return key;
}
+function copyTextToClipboard(target) {
+ if (target) {
+ var temp = document.createElement('textarea');
+ temp.value = target.getAttribute('data-clipboard-text');
+ document.body.appendChild(temp);
+ temp.select();
+ document.execCommand('copy');
+ if (temp.parentNode) {
+ temp.parentNode.removeChild(temp);
+ }
+
+ $(target.nextElementSibling).show().delay(2000).fadeOut(300);
+ }
+ return false;
+}
+
function updateIssueFrom(url, el) {
$('#all_attributes input, #all_attributes textarea, #all_attributes select').each(function(){
$(this).data('valuebeforeupdate', $(this).val());
diff --git a/public/stylesheets/application.css b/public/stylesheets/application.css
index da96a7d8d..5e8730688 100644
--- a/public/stylesheets/application.css
+++ b/public/stylesheets/application.css
@@ -596,6 +596,22 @@ div.journal h4 img.gravatar {margin-left:-32px;}
#history div:target h4.note-header {background-color:#DDEEFF;}
#history p.nodata {display: none;}
+.copy-link-wrapper {
+ display: inline; position: relative;
+}
+.copy-link-wrapper .success-copied-message {
+ display: none;
+ z-index: 25;
+ position: absolute;
+ border: 1px solid #555;
+ background-color: #fff;
+ padding: 4px;
+ font-size: 0.8em;
+ color: #453f3f;
+ top: 15px;
+ right: 0px;
+}
+
div#activity dl, #search-results { margin-left: 2em; }
div#activity dd, #search-results dd { margin-bottom: 1em; padding-left: 18px; font-size: 0.9em; }
div#activity dt.me .time { border-bottom: 1px solid #999; }
@@ -1607,6 +1623,7 @@ td.gantt_selected_column .gantt_hdr,.gantt_selected_column_container {
.icon-file.application-pdf { background-image: url(../images/files/pdf.png); }
.icon-file.application-zip { background-image: url(../images/files/zip.png); }
.icon-file.application-gzip { background-image: url(../images/files/zip.png); }
+.icon-copy-link { background-image: url(../images/page_link.png); }
.sort-handle.ajax-loading { background-image: url(../images/loading.gif); }
tr.ui-sortable-helper { border:1px solid #e4e4e4; }