{{ctx.RenderUtils.RenderCommitBody .LatestCommit.Message ($.Repository.ComposeMetas ctx)}}
{{end}}
diff --git a/templates/repo/view_file.tmpl b/templates/repo/view_file.tmpl
index 9f1b2a5e8f..51a8f7d501 100644
--- a/templates/repo/view_file.tmpl
+++ b/templates/repo/view_file.tmpl
@@ -55,7 +55,7 @@
{{end}}
{{svg "octicon-download"}}
- {{svg "octicon-copy"}}
+ {{svg "octicon-copy"}}
{{if .EnableFeed}}
{{svg "octicon-rss"}}
diff --git a/web_src/js/features/common-button.ts b/web_src/js/features/common-button.ts
index 7aebdd8dd5..003bfbce5d 100644
--- a/web_src/js/features/common-button.ts
+++ b/web_src/js/features/common-button.ts
@@ -1,5 +1,5 @@
import {POST} from '../modules/fetch.ts';
-import {addDelegatedEventListener, hideElem, queryElems, showElem, toggleElem} from '../utils/dom.ts';
+import {addDelegatedEventListener, hideElem, showElem, toggleElem} from '../utils/dom.ts';
import {fomanticQuery} from '../modules/fomantic/base.ts';
import {camelize} from 'vue';
@@ -74,10 +74,9 @@ export function initGlobalDeleteButton(): void {
}
}
-function onShowPanelClick(e: MouseEvent) {
+function onShowPanelClick(el: HTMLElement, e: MouseEvent) {
// a '.show-panel' element can show a panel, by `data-panel="selector"`
// if it has "toggle" class, it toggles the panel
- const el = e.currentTarget as HTMLElement;
e.preventDefault();
const sel = el.getAttribute('data-panel');
if (el.classList.contains('toggle')) {
@@ -87,9 +86,8 @@ function onShowPanelClick(e: MouseEvent) {
}
}
-function onHidePanelClick(e: MouseEvent) {
+function onHidePanelClick(el: HTMLElement, e: MouseEvent) {
// a `.hide-panel` element can hide a panel, by `data-panel="selector"` or `data-panel-closest="selector"`
- const el = e.currentTarget as HTMLElement;
e.preventDefault();
let sel = el.getAttribute('data-panel');
if (sel) {
@@ -104,7 +102,7 @@ function onHidePanelClick(e: MouseEvent) {
throw new Error('no panel to hide'); // should never happen, otherwise there is a bug in code
}
-function onShowModalClick(e: MouseEvent) {
+function onShowModalClick(el: HTMLElement, e: MouseEvent) {
// A ".show-modal" button will show a modal dialog defined by its "data-modal" attribute.
// Each "data-modal-{target}" attribute will be filled to target element's value or text-content.
// * First, try to query '#target'
@@ -112,7 +110,6 @@ function onShowModalClick(e: MouseEvent) {
// * Then, try to query '.target'
// * Then, try to query 'target' as HTML tag
// If there is a ".{attr}" part like "data-modal-form.action", then the form's "action" attribute will be set.
- const el = e.currentTarget as HTMLElement;
e.preventDefault();
const modalSelector = el.getAttribute('data-modal');
const elModal = document.querySelector(modalSelector);
@@ -160,7 +157,15 @@ export function initGlobalButtons(): void {
// There are a few cancel buttons in non-modal forms, and there are some dynamically created forms (eg: the "Edit Issue Content")
addDelegatedEventListener(document, 'click', 'form button.ui.cancel.button', (_ /* el */, e) => e.preventDefault());
- queryElems(document, '.show-panel', (el) => el.addEventListener('click', onShowPanelClick));
- queryElems(document, '.hide-panel', (el) => el.addEventListener('click', onHidePanelClick));
- queryElems(document, '.show-modal', (el) => el.addEventListener('click', onShowModalClick));
+ // Ideally these "button" events should be handled by registerGlobalEventFunc
+ // Refactoring would involve too many changes, so at the moment, just use the global event listener.
+ addDelegatedEventListener(document, 'click', '.show-panel, .hide-panel, .show-modal', (el, e: MouseEvent) => {
+ if (el.classList.contains('show-panel')) {
+ onShowPanelClick(el, e);
+ } else if (el.classList.contains('hide-panel')) {
+ onHidePanelClick(el, e);
+ } else if (el.classList.contains('show-modal')) {
+ onShowModalClick(el, e);
+ }
+ });
}
diff --git a/web_src/js/features/copycontent.ts b/web_src/js/features/copycontent.ts
index 4bc9281a35..3961a8d7ac 100644
--- a/web_src/js/features/copycontent.ts
+++ b/web_src/js/features/copycontent.ts
@@ -2,21 +2,19 @@ import {clippie} from 'clippie';
import {showTemporaryTooltip} from '../modules/tippy.ts';
import {convertImage} from '../utils.ts';
import {GET} from '../modules/fetch.ts';
+import {registerGlobalEventFunc} from '../modules/observer.ts';
const {i18n} = window.config;
export function initCopyContent() {
- const btn = document.querySelector('#copy-content');
- if (!btn || btn.classList.contains('disabled')) return;
-
- btn.addEventListener('click', async () => {
- if (btn.classList.contains('is-loading')) return;
+ registerGlobalEventFunc('click', 'onCopyContentButtonClick', async (btn: HTMLInputElement) => {
+ if (btn.classList.contains('disabled') || btn.classList.contains('is-loading')) return;
let content;
let isRasterImage = false;
const link = btn.getAttribute('data-link');
// when data-link is present, we perform a fetch. this is either because
- // the text to copy is not in the DOM or it is an image which should be
+ // the text to copy is not in the DOM, or it is an image which should be
// fetched to copy in full resolution
if (link) {
btn.classList.add('is-loading', 'loading-icon-2px');
@@ -40,7 +38,7 @@ export function initCopyContent() {
content = Array.from(lineEls, (el) => el.textContent).join('');
}
- // try copy original first, if that fails and it's an image, convert it to png
+ // try copy original first, if that fails, and it's an image, convert it to png
const success = await clippie(content);
if (success) {
showTemporaryTooltip(btn, i18n.copy_success);
diff --git a/web_src/js/features/repo-commit.ts b/web_src/js/features/repo-commit.ts
index 8994a57f4a..e6d1112778 100644
--- a/web_src/js/features/repo-commit.ts
+++ b/web_src/js/features/repo-commit.ts
@@ -1,15 +1,14 @@
import {createTippy} from '../modules/tippy.ts';
import {toggleElem} from '../utils/dom.ts';
+import {registerGlobalEventFunc} from '../modules/observer.ts';
export function initRepoEllipsisButton() {
- for (const button of document.querySelectorAll