]> source.dussan.org Git - gitea.git/commitdiff
Replace clipboard.js with async clipboard api (#15899)
authorsilverwind <me@silverwind.io>
Sun, 30 May 2021 19:15:57 +0000 (21:15 +0200)
committerGitHub <noreply@github.com>
Sun, 30 May 2021 19:15:57 +0000 (20:15 +0100)
Use async clipboard api [1] over this dependency, saving around 10kB
bundle size before minify while delivering the same functionality.

The issue comment button works but does not have a popup indication. We
could add some toast-style notifications in the future to fix that but I
think it's out of scope of this PR.

[1] https://developer.mozilla.org/en-US/docs/Web/API/Clipboard/writeText

package-lock.json
package.json
templates/repo/clone_buttons.tmpl
templates/repo/issue/view_content/context_menu.tmpl
web_src/js/features/clipboard.js

index 0ec6f4345605ceb4b496aec628582f72f2bbf49b..43f1b6f45f8973c0d20c2b58bfa9b136a2921216 100644 (file)
@@ -9,7 +9,6 @@
         "@claviska/jquery-minicolors": "2.3.5",
         "@primer/octicons": "13.0.0",
         "add-asset-webpack-plugin": "2.0.1",
-        "clipboard": "2.0.8",
         "codemirror": "5.61.0",
         "css-loader": "5.2.4",
         "dropzone": "5.9.2",
         "node": ">=4"
       }
     },
-    "node_modules/clipboard": {
-      "version": "2.0.8",
-      "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.8.tgz",
-      "integrity": "sha512-Y6WO0unAIQp5bLmk1zdThRhgJt/x3ks6f30s3oE3H1mgIEU33XyQjEf8gsf6DxC7NPX8Y1SsNWjUjL/ywLnnbQ==",
-      "dependencies": {
-        "good-listener": "^1.2.2",
-        "select": "^1.1.2",
-        "tiny-emitter": "^2.0.0"
-      }
-    },
     "node_modules/cliui": {
       "version": "6.0.0",
       "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
         "node": ">=0.4.0"
       }
     },
-    "node_modules/delegate": {
-      "version": "3.2.0",
-      "resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz",
-      "integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw=="
-    },
     "node_modules/detect-newline": {
       "version": "3.1.0",
       "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz",
         "node": ">=0.6.0"
       }
     },
-    "node_modules/good-listener": {
-      "version": "1.2.2",
-      "resolved": "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz",
-      "integrity": "sha1-1TswzfkxPf+33JoNR3CWqm0UXFA=",
-      "dependencies": {
-        "delegate": "^3.1.2"
-      }
-    },
     "node_modules/graceful-fs": {
       "version": "4.2.6",
       "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz",
         "url": "https://opencollective.com/webpack"
       }
     },
-    "node_modules/select": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz",
-      "integrity": "sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0="
-    },
     "node_modules/semver": {
       "version": "7.3.5",
       "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
       "integrity": "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==",
       "dev": true
     },
-    "node_modules/tiny-emitter": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz",
-      "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q=="
-    },
     "node_modules/tmpl": {
       "version": "1.0.4",
       "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz",
         "escape-string-regexp": "^1.0.5"
       }
     },
-    "clipboard": {
-      "version": "2.0.8",
-      "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.8.tgz",
-      "integrity": "sha512-Y6WO0unAIQp5bLmk1zdThRhgJt/x3ks6f30s3oE3H1mgIEU33XyQjEf8gsf6DxC7NPX8Y1SsNWjUjL/ywLnnbQ==",
-      "requires": {
-        "good-listener": "^1.2.2",
-        "select": "^1.1.2",
-        "tiny-emitter": "^2.0.0"
-      }
-    },
     "cliui": {
       "version": "6.0.0",
       "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
       "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
       "dev": true
     },
-    "delegate": {
-      "version": "3.2.0",
-      "resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz",
-      "integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw=="
-    },
     "detect-newline": {
       "version": "3.1.0",
       "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz",
         "minimist": "^1.2.5"
       }
     },
-    "good-listener": {
-      "version": "1.2.2",
-      "resolved": "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz",
-      "integrity": "sha1-1TswzfkxPf+33JoNR3CWqm0UXFA=",
-      "requires": {
-        "delegate": "^3.1.2"
-      }
-    },
     "graceful-fs": {
       "version": "4.2.6",
       "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz",
         "ajv-keywords": "^3.5.2"
       }
     },
-    "select": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz",
-      "integrity": "sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0="
-    },
     "semver": {
       "version": "7.3.5",
       "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
       "integrity": "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==",
       "dev": true
     },
-    "tiny-emitter": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz",
-      "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q=="
-    },
     "tmpl": {
       "version": "1.0.4",
       "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz",
index 5da3dfab20800d6d77cfac4d6e7d62d1e32e2bd6..bbd56580318139efc5d938ce8faadcf5462bf0fa 100644 (file)
@@ -9,7 +9,6 @@
     "@claviska/jquery-minicolors": "2.3.5",
     "@primer/octicons": "13.0.0",
     "add-asset-webpack-plugin": "2.0.1",
-    "clipboard": "2.0.8",
     "codemirror": "5.61.0",
     "css-loader": "5.2.4",
     "dropzone": "5.9.2",
index b0377b5bc34d7f3dc3372fed1bcb977dc264db18..8fc1ba12c13d37f19d9ebda4d169040671b64743 100644 (file)
@@ -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 clipboard" 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-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">
                {{svg "octicon-clippy"}}
        </button>
 {{end}}
index bbffd53460419ec9dbed0a48f1857541da79818d..e3001cddce5a8420e448a398f903482bff2db3c7 100644 (file)
@@ -10,7 +10,7 @@
                {{ else }}
                        {{ $referenceUrl = Printf "%s%s/pulls/%d/files#%s" AppUrl .ctx.Repository.FullName .ctx.Issue.Index .item.HashTag }}
                {{ end }}
-               <div class="item context clipboard" data-clipboard-text="{{$referenceUrl}}">{{.ctx.i18n.Tr "repo.issues.context.copy_link"}}</div>
+               <div class="item context" data-clipboard-text="{{$referenceUrl}}">{{.ctx.i18n.Tr "repo.issues.context.copy_link"}}</div>
                <div class="item context quote-reply {{if .diff}}quote-reply-diff{{end}}" data-target="{{.item.ID}}">{{.ctx.i18n.Tr "repo.issues.context.quote_reply"}}</div>
                {{if not .ctx.UnitIssuesGlobalDisabled}}
                        <div class="item context reference-issue" data-target="{{.item.ID}}" data-modal="#reference-issue-modal" data-poster="{{.item.Poster.GetDisplayName}}" data-reference="{{$referenceUrl}}">{{.ctx.i18n.Tr "repo.issues.context.reference_issue"}}</div>
index 32eff981b8fc67bb907fa5eea21856b96b720a02..12486a208d5a3632269e22bafedded02ddb15c2e 100644 (file)
@@ -1,22 +1,38 @@
-export default async function initClipboard() {
-  const els = document.querySelectorAll('.clipboard');
-  if (!els || !els.length) return;
+const selector = '[data-clipboard-target], [data-clipboard-text]';
 
-  const {default: ClipboardJS} = await import(/* webpackChunkName: "clipboard" */'clipboard');
+// TODO: replace these with toast-style notifications
+function onSuccess(btn) {
+  if (!btn.dataset.content) return;
+  $(btn).popup('destroy');
+  btn.dataset.content = btn.dataset.success;
+  $(btn).popup('show');
+  btn.dataset.content = btn.dataset.original;
+}
+function onError(btn) {
+  if (!btn.dataset.content) return;
+  $(btn).popup('destroy');
+  btn.dataset.content = btn.dataset.error;
+  $(btn).popup('show');
+  btn.dataset.content = btn.dataset.original;
+}
 
-  const clipboard = new ClipboardJS(els);
-  clipboard.on('success', (e) => {
-    e.clearSelection();
-    $(e.trigger).popup('destroy');
-    e.trigger.dataset.content = e.trigger.dataset.success;
-    $(e.trigger).popup('show');
-    e.trigger.dataset.content = e.trigger.dataset.original;
-  });
+export default async function initClipboard() {
+  for (const btn of document.querySelectorAll(selector) || []) {
+    btn.addEventListener('click', async () => {
+      let text;
+      if (btn.dataset.clipboardText) {
+        text = btn.dataset.clipboardText;
+      } else if (btn.dataset.clipboardTarget) {
+        text = document.querySelector(btn.dataset.clipboardTarget)?.value;
+      }
+      if (!text) return;
 
-  clipboard.on('error', (e) => {
-    $(e.trigger).popup('destroy');
-    e.trigger.dataset.content = e.trigger.dataset.error;
-    $(e.trigger).popup('show');
-    e.trigger.dataset.content = e.trigger.dataset.original;
-  });
+      try {
+        await navigator.clipboard.writeText(text);
+        onSuccess(btn);
+      } catch {
+        onError(btn);
+      }
+    });
+  }
 }