diff --git a/templates/base/head.tmpl b/templates/base/head.tmpl index 70a88ff75569a..b0326e09828e2 100644 --- a/templates/base/head.tmpl +++ b/templates/base/head.tmpl @@ -23,6 +23,7 @@ <link rel="alternate icon" href="{{AssetUrlPrefix}}/img/favicon.png" type="image/png"> <link rel="stylesheet" href="{{AssetUrlPrefix}}/css/index.css?v={{AssetVersion}}"> {{template "base/head_script" .}} + <script src="{{AssetUrlPrefix}}/js/init.js?v={{AssetVersion}}"></script> <noscript> <style> .dropdown:hover > .menu { display: block; } diff --git a/templates/repo/clone_script.tmpl b/templates/repo/clone_script.tmpl deleted file mode 100644 index afd90040fb4e7..0000000000000 --- a/templates/repo/clone_script.tmpl +++ /dev/null @@ -1,28 +0,0 @@ -<script> - // synchronously set clone button states and urls here to avoid flickering - // on page load. initRepoCloneLink calls this when proto changes. - // this applies the protocol-dependant clone url to all elements with the - // `js-clone-url` and `js-clone-url-vsc` classes. - // TODO: This localStorage setting should be moved to backend user config - // so it's available during rendering, then this inline script can be removed. - (window.updateCloneStates = function() { - const httpsBtn = document.getElementById('repo-clone-https'); - const sshBtn = document.getElementById('repo-clone-ssh'); - const value = localStorage.getItem('repo-clone-protocol') || 'https'; - const isSSH = value === 'ssh' && sshBtn || value !== 'ssh' && !httpsBtn; - - if (httpsBtn) httpsBtn.classList[!isSSH ? 'add' : 'remove']('primary'); - if (sshBtn) sshBtn.classList[isSSH ? 'add' : 'remove']('primary'); - - const btn = isSSH ? sshBtn : httpsBtn; - if (!btn) return; - - const link = btn.getAttribute('data-link'); - for (const el of document.getElementsByClassName('js-clone-url')) { - el[el.nodeName === 'INPUT' ? 'value' : 'textContent'] = link; - } - for (const el of document.getElementsByClassName('js-clone-url-vsc')) { - el['href'] = 'vscode://vscode.git/clone?url=' + encodeURIComponent(link); - } - })(); -</script> diff --git a/templates/repo/empty.tmpl b/templates/repo/empty.tmpl index 24547758a7f4b..3e52fbac189d6 100644 --- a/templates/repo/empty.tmpl +++ b/templates/repo/empty.tmpl @@ -50,7 +50,6 @@ git push -u origin {{.Repository.DefaultBranch}}</code></pre> git push -u origin {{.Repository.DefaultBranch}}</code></pre> </div> </div> - {{template "repo/clone_script" .}} {{end}} {{else}} <div class="ui segment center"> diff --git a/templates/repo/home.tmpl b/templates/repo/home.tmpl index e1aa1c4f3b45b..c636524aa3953 100644 --- a/templates/repo/home.tmpl +++ b/templates/repo/home.tmpl @@ -128,7 +128,6 @@ <a class="item js-clone-url-vsc" href="vscode://vscode.git/clone?url={{.CloneButtonOriginLink.HTTPS}}">{{svg "gitea-vscode" 16 "mr-3"}}{{.locale.Tr "repo.clone_in_vsc"}}</a> </div> </button> - {{template "repo/clone_script" .}}{{/* the script will update `.js-clone-url` and related elements */}} </div> {{end}} {{if and (ne $n 0) (not .IsViewFile) (not .IsBlame)}} diff --git a/templates/repo/wiki/revision.tmpl b/templates/repo/wiki/revision.tmpl index b49441f4eb844..da2395c2dd549 100644 --- a/templates/repo/wiki/revision.tmpl +++ b/templates/repo/wiki/revision.tmpl @@ -7,7 +7,6 @@ <div class="ui eight wide column text right df ac je"> <div class="ui action small input" id="clone-panel"> {{template "repo/clone_buttons" .}} - {{template "repo/clone_script" .}} </div> </div> <div class="ui header eight wide column"> diff --git a/templates/repo/wiki/view.tmpl b/templates/repo/wiki/view.tmpl index 3cd6617dd9ad1..6d991a8ea9aa5 100644 --- a/templates/repo/wiki/view.tmpl +++ b/templates/repo/wiki/view.tmpl @@ -31,7 +31,6 @@ <div class="df ac"> <div class="ui action small input" id="clone-panel"> {{template "repo/clone_buttons" .}} - {{template "repo/clone_script" .}} </div> </div> </div> diff --git a/web_src/js/init.js b/web_src/js/init.js new file mode 100644 index 0000000000000..79fc4bfaae02d --- /dev/null +++ b/web_src/js/init.js @@ -0,0 +1,39 @@ +// This script is for critical JS that needs to perform DOM mutations +// before the initial browser paint. + +let attempts = 0; +window.requestAnimationFrame(function wait() { + if (document.querySelector('script[src*="index.js"]') || ++attempts > 100) return init(); + window.requestAnimationFrame(wait); +}); + +// This function runs before DOMContentLoaded and checks if most of the page +// has loaded so we can do DOM mutations before anything is painted on the screen. +function init() { + // Synchronously set clone button states and urls here to avoid flickering + // on page load. initRepoCloneLink calls this when proto changes. + // this applies the protocol-dependant clone url to all elements with the + // `js-clone-url` and `js-clone-url-vsc` classes. + // TODO: This localStorage setting should be moved to backend user config. + (window.updateCloneStates = function() { + const httpsBtn = document.getElementById('repo-clone-https'); + if (!httpsBtn) return; + const sshBtn = document.getElementById('repo-clone-ssh'); + const value = localStorage.getItem('repo-clone-protocol') || 'https'; + const isSSH = value === 'ssh' && sshBtn || value !== 'ssh' && !httpsBtn; + + if (httpsBtn) httpsBtn.classList[!isSSH ? 'add' : 'remove']('primary'); + if (sshBtn) sshBtn.classList[isSSH ? 'add' : 'remove']('primary'); + + const btn = isSSH ? sshBtn : httpsBtn; + if (!btn) return; + + const link = btn.getAttribute('data-link'); + for (const el of document.getElementsByClassName('js-clone-url')) { + el[el.nodeName === 'INPUT' ? 'value' : 'textContent'] = link; + } + for (const el of document.getElementsByClassName('js-clone-url-vsc')) { + el.href = `vscode://vscode.git/clone?url=${encodeURIComponent(link)}`; + } + })(); +} diff --git a/webpack.config.js b/webpack.config.js index 26632429929b9..3466b21d43af3 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -50,6 +50,9 @@ const filterCssImport = (url, ...args) => { export default { mode: isProduction ? 'production' : 'development', entry: { + init: [ + fileURLToPath(new URL('web_src/js/init.js', import.meta.url)), + ], index: [ fileURLToPath(new URL('web_src/js/jquery.js', import.meta.url)), fileURLToPath(new URL('web_src/fomantic/build/semantic.js', import.meta.url)),