From 0208ea0248782a994771cadf0af6a4125fdde723 Mon Sep 17 00:00:00 2001
From: Mario Lubenka <mario.lubenka@googlemail.com>
Date: Tue, 19 Oct 2021 19:32:11 +0200
Subject: [PATCH]  "Copy branch name" button in pull request (#17323)

* Drop data-original from clipboard

data-original attribute was removed. Instead, the original value from
data-content is set after success/fail message was displayed.

Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com>

* "Copy branch name" button in pull request

Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com>

* Update templates/repo/issue/view_title.tmpl

Co-authored-by: silverwind <me@silverwind.io>

* Apply suggestions from code review

Co-authored-by: zeripath <art27@cantab.net>

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: zeripath <art27@cantab.net>
---
 options/locale/locale_en-US.ini      |  3 +++
 templates/repo/clone_buttons.tmpl    |  2 +-
 templates/repo/issue/view_title.tmpl | 13 +++++++------
 web_src/js/features/clipboard.js     |  6 ++++--
 web_src/less/_repository.less        |  9 +++++++++
 5 files changed, 24 insertions(+), 9 deletions(-)

diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini
index 407ec9f84e..22fe9ae2f8 100644
--- a/options/locale/locale_en-US.ini
+++ b/options/locale/locale_en-US.ini
@@ -927,6 +927,9 @@ star_guest_user = Sign in to star this repository.
 copy_link = Copy
 copy_link_success = Link has been copied
 copy_link_error = Use ⌘C or Ctrl-C to copy
+copy_branch = Copy
+copy_branch_success = Branch name has been copied
+copy_branch_error = Use ⌘C or Ctrl-C to copy
 copied = Copied OK
 unwatch = Unwatch
 watch = Watch
diff --git a/templates/repo/clone_buttons.tmpl b/templates/repo/clone_buttons.tmpl
index 9eb7fa781d..0a86e586fc 100644
--- a/templates/repo/clone_buttons.tmpl
+++ b/templates/repo/clone_buttons.tmpl
@@ -14,7 +14,7 @@
 	<input id="repo-clone-url" value="{{if $.PageIsWiki}}{{$.WikiCloneLink.SSH}}{{else}}{{$.CloneLink.SSH}}{{end}}" readonly>
 {{end}}
 {{if or (not $.DisableHTTP) (and (not $.DisableSSH) (or $.IsSigned $.ExposeAnonSSH))}}
-	<button class="ui basic icon button poping up" id="clipboard-btn" data-original="{{.i18n.Tr "repo.copy_link"}}" data-success="{{.i18n.Tr "repo.copy_link_success"}}" data-error="{{.i18n.Tr "repo.copy_link_error"}}" data-content="{{.i18n.Tr "repo.copy_link"}}" data-variation="inverted tiny" data-clipboard-target="#repo-clone-url">
+	<button class="ui basic icon button poping up" id="clipboard-btn" data-success="{{.i18n.Tr "repo.copy_link_success"}}" data-error="{{.i18n.Tr "repo.copy_link_error"}}" data-content="{{.i18n.Tr "repo.copy_link"}}" data-variation="inverted tiny" data-clipboard-target="#repo-clone-url">
 		{{svg "octicon-paste"}}
 	</button>
 {{end}}
diff --git a/templates/repo/issue/view_title.tmpl b/templates/repo/issue/view_title.tmpl
index b6bf965a15..798ab7638c 100644
--- a/templates/repo/issue/view_title.tmpl
+++ b/templates/repo/issue/view_title.tmpl
@@ -32,28 +32,29 @@
 	{{if .Issue.IsPull}}
 		{{$headHref := .HeadTarget|Escape}}
 		{{if .HeadBranchHTMLURL}}
-			{{$headHref = printf "<a href=\"%s\">%s</a>" .HeadBranchHTMLURL $headHref}}
+			{{$headHref = printf "<a href=\"%s\">%s</a>" (.HeadBranchHTMLURL | Escape) $headHref}}
 		{{end}}
+		{{$headHref = printf "%s <a class=\"poping up\" data-content=\"%s\" data-success=\"%s\" data-error=\"%s\" data-clipboard-text=\"%s\" data-variation=\"inverted tiny\">%s</a>" $headHref (.i18n.Tr "repo.copy_branch") (.i18n.Tr "repo.copy_branch_success") (.i18n.Tr "repo.copy_branch_error") (.HeadTarget | Escape) (svg "octicon-copy" 14)}}
 		{{$baseHref := .BaseTarget|Escape}}
 		{{if .BaseBranchHTMLURL}}
-			{{$baseHref = printf "<a href=\"%s\">%s</a>" .BaseBranchHTMLURL $baseHref}}
+			{{$baseHref = printf "<a href=\"%s\">%s</a>" (.BaseBranchHTMLURL | Escape) $baseHref}}
 		{{end}}
 		{{if .Issue.PullRequest.HasMerged}}
 			{{ $mergedStr:= TimeSinceUnix .Issue.PullRequest.MergedUnix $.Lang }}
 			{{if .Issue.OriginalAuthor }}
 				{{.Issue.OriginalAuthor}}
-				<span class="pull-desc">{{$.i18n.Tr "repo.pulls.merged_title_desc" .NumCommits $headHref $baseHref $mergedStr | Str2html}}</span>
+				<span class="pull-desc">{{$.i18n.Tr "repo.pulls.merged_title_desc" .NumCommits $headHref $baseHref $mergedStr | Safe}}</span>
 			{{else}}
 				<a {{if gt .Issue.PullRequest.Merger.ID 0}}href="{{.Issue.PullRequest.Merger.HomeLink}}"{{end}}>{{.Issue.PullRequest.Merger.GetDisplayName}}</a>
-				<span class="pull-desc">{{$.i18n.Tr "repo.pulls.merged_title_desc" .NumCommits $headHref $baseHref $mergedStr | Str2html}}</span>
+				<span class="pull-desc">{{$.i18n.Tr "repo.pulls.merged_title_desc" .NumCommits $headHref $baseHref $mergedStr | Safe}}</span>
 			{{end}}
 		{{else}}
 			{{if .Issue.OriginalAuthor }}
-				<span id="pull-desc" class="pull-desc">{{.Issue.OriginalAuthor}} {{$.i18n.Tr "repo.pulls.title_desc" .NumCommits $headHref $baseHref | Str2html}}</span>
+				<span id="pull-desc" class="pull-desc">{{.Issue.OriginalAuthor}} {{$.i18n.Tr "repo.pulls.title_desc" .NumCommits $headHref $baseHref | Safe}}</span>
 			{{else}}
 				<span id="pull-desc" class="pull-desc">
 					<a {{if gt .Issue.Poster.ID 0}}href="{{.Issue.Poster.HomeLink}}"{{end}}>{{.Issue.Poster.GetDisplayName}}</a>
-					{{$.i18n.Tr "repo.pulls.title_desc" .NumCommits $headHref $baseHref | Str2html}}
+					{{$.i18n.Tr "repo.pulls.title_desc" .NumCommits $headHref $baseHref | Safe}}
 				</span>
 			{{end}}
 			<span id="pull-desc-edit" style="display: none">
diff --git a/web_src/js/features/clipboard.js b/web_src/js/features/clipboard.js
index 2c7ad013bd..8d28b4e281 100644
--- a/web_src/js/features/clipboard.js
+++ b/web_src/js/features/clipboard.js
@@ -4,16 +4,18 @@
 function onSuccess(btn) {
   if (!btn.dataset.content) return;
   $(btn).popup('destroy');
+  const oldContent = btn.dataset.content;
   btn.dataset.content = btn.dataset.success;
   $(btn).popup('show');
-  btn.dataset.content = btn.dataset.original;
+  btn.dataset.content = oldContent;
 }
 function onError(btn) {
   if (!btn.dataset.content) return;
+  const oldContent = btn.dataset.content;
   $(btn).popup('destroy');
   btn.dataset.content = btn.dataset.error;
   $(btn).popup('show');
-  btn.dataset.content = btn.dataset.original;
+  btn.dataset.content = oldContent;
 }
 
 /**
diff --git a/web_src/less/_repository.less b/web_src/less/_repository.less
index 8f9c5ba6b5..cddc2c2e7d 100644
--- a/web_src/less/_repository.less
+++ b/web_src/less/_repository.less
@@ -686,6 +686,15 @@
       code {
         color: var(--color-primary);
       }
+      a[data-clipboard-text] {
+        cursor: pointer;
+        svg {
+          vertical-align: middle;
+          position: relative;
+          top: -2px;
+          right: 1px;
+        }
+      }
     }
 
     .pull {