From 925a3f38f4f84ecdd3d43acb3a948719dd6bccbd Mon Sep 17 00:00:00 2001 From: silverwind Date: Tue, 18 Jul 2023 00:54:34 +0200 Subject: [PATCH 01/24] Enable Webpack ESM output and move to /static/ asset directory --- .dockerignore | 5 +- .gitignore | 5 +- Makefile | 4 +- package-lock.json | 12 -- package.json | 1 - public/index.css | 0 public/index.js | 0 templates/base/footer.tmpl | 2 +- templates/base/footer_content.tmpl | 2 +- templates/base/head_script.tmpl | 2 +- templates/base/head_style.tmpl | 6 +- templates/devtest/gitea-ui.tmpl | 4 +- templates/swagger/ui.tmpl | 4 +- web_src/css/index.css | 4 + web_src/js/bootstrap.js | 6 +- web_src/js/features/common-global.js | 2 +- web_src/js/features/notification.js | 2 +- web_src/js/features/stopwatch.js | 2 +- web_src/js/index.js | 1 + web_src/js/jquery.js | 3 - web_src/js/utils.js | 10 -- web_src/js/utils.test.js | 41 +----- web_src/js/vendor/ays.js | 181 +++++++++++++++++++++++++++ webpack.config.js | 39 +++--- 24 files changed, 225 insertions(+), 113 deletions(-) create mode 100644 public/index.css create mode 100644 public/index.js delete mode 100644 web_src/js/jquery.js create mode 100644 web_src/js/vendor/ays.js diff --git a/.dockerignore b/.dockerignore index 2a4142088908e..6a2dea4c8e417 100644 --- a/.dockerignore +++ b/.dockerignore @@ -75,10 +75,7 @@ cpu.out /yarn.lock /yarn-error.log /npm-debug.log* -/public/js -/public/css -/public/fonts -/public/img/webpack +/public/static /vendor /web_src/fomantic/node_modules /web_src/fomantic/build/* diff --git a/.gitignore b/.gitignore index 6851be742c641..a7eddf9068b77 100644 --- a/.gitignore +++ b/.gitignore @@ -72,10 +72,7 @@ cpu.out /yarn.lock /yarn-error.log /npm-debug.log* -/public/js -/public/css -/public/fonts -/public/img/webpack +/public/static /vendor /web_src/fomantic/node_modules /web_src/fomantic/build/* diff --git a/Makefile b/Makefile index 7de96f09fdd18..1e47ab3f28203 100644 --- a/Makefile +++ b/Makefile @@ -116,8 +116,8 @@ FOMANTIC_WORK_DIR := web_src/fomantic WEBPACK_SOURCES := $(shell find web_src/js web_src/css -type f) WEBPACK_CONFIGS := webpack.config.js -WEBPACK_DEST := public/js/index.js public/css/index.css -WEBPACK_DEST_ENTRIES := public/js public/css public/fonts public/img/webpack +WEBPACK_DEST := public/index.js public/index.css +WEBPACK_DEST_ENTRIES := /public/static BINDATA_DEST := modules/public/bindata.go modules/options/bindata.go modules/templates/bindata.go BINDATA_HASH := $(addsuffix .hash,$(BINDATA_DEST)) diff --git a/package-lock.json b/package-lock.json index 92e4087b08495..ee2fff67af824 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,7 +27,6 @@ "escape-goat": "4.0.0", "fast-glob": "3.3.0", "jquery": "3.7.0", - "jquery.are-you-sure": "1.9.0", "katex": "0.16.8", "license-checker-webpack-plugin": "0.2.1", "lightningcss-loader": "2.1.0", @@ -6408,17 +6407,6 @@ "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.0.tgz", "integrity": "sha512-umpJ0/k8X0MvD1ds0P9SfowREz2LenHsQaxSohMZ5OMNEU2r0tf8pdeEFTHMFxWVxKNyU9rTtK3CWzUCTKJUeQ==" }, - "node_modules/jquery.are-you-sure": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/jquery.are-you-sure/-/jquery.are-you-sure-1.9.0.tgz", - "integrity": "sha512-2r0uFx8CyAopjeHGOdvvwpFP921TnW1+v1uJXcAWQYHYGB1tryTDhQY+5u6HsVeMwbWiRTKVZFWnLaFpDvIqZQ==", - "dependencies": { - "jquery": ">=1.4.2" - }, - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/js-levenshtein-esm": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/js-levenshtein-esm/-/js-levenshtein-esm-1.2.0.tgz", diff --git a/package.json b/package.json index 10956595b6891..9579d5929e7d4 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,6 @@ "escape-goat": "4.0.0", "fast-glob": "3.3.0", "jquery": "3.7.0", - "jquery.are-you-sure": "1.9.0", "katex": "0.16.8", "license-checker-webpack-plugin": "0.2.1", "lightningcss-loader": "2.1.0", diff --git a/public/index.css b/public/index.css new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/public/index.js b/public/index.js new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/templates/base/footer.tmpl b/templates/base/footer.tmpl index e3cac806a4d91..14ede627a7f41 100644 --- a/templates/base/footer.tmpl +++ b/templates/base/footer.tmpl @@ -25,7 +25,7 @@ {{end}} {{end}} - + {{template "custom/footer" .}} diff --git a/templates/base/footer_content.tmpl b/templates/base/footer_content.tmpl index 3b87f25d63786..43c77f0f31179 100644 --- a/templates/base/footer_content.tmpl +++ b/templates/base/footer_content.tmpl @@ -23,7 +23,7 @@ {{end}} - {{.locale.Tr "licenses"}} + {{.locale.Tr "licenses"}} {{if .EnableSwagger}}API{{end}} {{template "custom/extra_links_footer" .}} diff --git a/templates/base/head_script.tmpl b/templates/base/head_script.tmpl index c7477ff4c0f2e..ce1e080531d9a 100644 --- a/templates/base/head_script.tmpl +++ b/templates/base/head_script.tmpl @@ -44,4 +44,4 @@ If you introduce mistakes in it, Gitea JavaScript code wouldn't run correctly. {{/* in case some pages don't render the pageData, we make sure it is an object to prevent null access */}} window.config.pageData = window.config.pageData || {}; - + diff --git a/templates/base/head_style.tmpl b/templates/base/head_style.tmpl index 7e8cba2aedde0..f691451bfbcd2 100644 --- a/templates/base/head_style.tmpl +++ b/templates/base/head_style.tmpl @@ -1,8 +1,8 @@ - + {{if .IsSigned}} {{if ne .SignedUser.Theme "gitea"}} - + {{end}} {{else if ne DefaultTheme "gitea"}} - + {{end}} diff --git a/templates/devtest/gitea-ui.tmpl b/templates/devtest/gitea-ui.tmpl index 8b31957f2e0c4..4835843e42ea2 100644 --- a/templates/devtest/gitea-ui.tmpl +++ b/templates/devtest/gitea-ui.tmpl @@ -1,5 +1,5 @@ {{template "base/head" .}} - +

Button

@@ -252,6 +252,6 @@
ps: no JS code attached, so just a layout
{{template "shared/combomarkdowneditor" .}}
- +
{{template "base/footer" .}} diff --git a/templates/swagger/ui.tmpl b/templates/swagger/ui.tmpl index e2324f9b5baaf..639cc1ce19395 100644 --- a/templates/swagger/ui.tmpl +++ b/templates/swagger/ui.tmpl @@ -2,11 +2,11 @@ Gitea API - + {{svg "octicon-reply"}}{{.locale.Tr "return_to_gitea"}}
- + diff --git a/web_src/css/index.css b/web_src/css/index.css index fa918f49dad25..9b841dde021c5 100644 --- a/web_src/css/index.css +++ b/web_src/css/index.css @@ -1,3 +1,5 @@ +@import "../fomantic/build/semantic.css"; + @import "./modules/normalize.css"; @import "./modules/animations.css"; @import "./modules/button.css"; @@ -61,3 +63,5 @@ @import "./review.css"; @import "./actions.css"; @import "./helpers.css"; + +@import "easymde/dist/easymde.min.css"; diff --git a/web_src/js/bootstrap.js b/web_src/js/bootstrap.js index f0b020ce1cf62..d70be7dfb0bb6 100644 --- a/web_src/js/bootstrap.js +++ b/web_src/js/bootstrap.js @@ -1,11 +1,13 @@ -import {joinPaths} from './utils.js'; +import $ from 'jquery'; + +window.$ = window.jQuery = $; // DO NOT IMPORT window.config HERE! // to make sure the error handler always works, we should never import `window.config`, because some user's custom template breaks it. // This sets up the URL prefix used in webpack's chunk loading. // This file must be imported before any lazy-loading is being attempted. -__webpack_public_path__ = joinPaths(window?.config?.assetUrlPrefix ?? '/', '/'); +__webpack_public_path__ = `${window.config?.assetUrlPrefix}/static/`; export function showGlobalErrorMessage(msg) { const pageContent = document.querySelector('.page-content'); diff --git a/web_src/js/features/common-global.js b/web_src/js/features/common-global.js index 8ee5ce25bfc9e..4add7678a40ab 100644 --- a/web_src/js/features/common-global.js +++ b/web_src/js/features/common-global.js @@ -1,5 +1,5 @@ import $ from 'jquery'; -import 'jquery.are-you-sure'; +import '../vendor/ays.js'; import {createDropzone} from './dropzone.js'; import {initCompColorPicker} from './comp/ColorPicker.js'; import {showGlobalErrorMessage} from '../bootstrap.js'; diff --git a/web_src/js/features/notification.js b/web_src/js/features/notification.js index 4dcf02d2dca90..56f802296d383 100644 --- a/web_src/js/features/notification.js +++ b/web_src/js/features/notification.js @@ -81,7 +81,7 @@ export function initNotificationCount() { if (notificationSettings.EventSourceUpdateTime > 0 && window.EventSource && window.SharedWorker) { // Try to connect to the event source via the shared worker first - const worker = new SharedWorker(`${__webpack_public_path__}js/eventsource.sharedworker.js?v=${assetVersionEncoded}`, 'notification-worker'); + const worker = new SharedWorker(`${__webpack_public_path__}eventsource.sharedworker.js?v=${assetVersionEncoded}`, 'notification-worker'); worker.addEventListener('error', (event) => { console.error('worker error', event); }); diff --git a/web_src/js/features/stopwatch.js b/web_src/js/features/stopwatch.js index f43014fec5b7d..a59b9b2bee06e 100644 --- a/web_src/js/features/stopwatch.js +++ b/web_src/js/features/stopwatch.js @@ -43,7 +43,7 @@ export function initStopwatch() { // if the browser supports EventSource and SharedWorker, use it instead of the periodic poller if (notificationSettings.EventSourceUpdateTime > 0 && window.EventSource && window.SharedWorker) { // Try to connect to the event source via the shared worker first - const worker = new SharedWorker(`${__webpack_public_path__}js/eventsource.sharedworker.js?v=${assetVersionEncoded}`, 'notification-worker'); + const worker = new SharedWorker(`${__webpack_public_path__}eventsource.sharedworker.js?v=${assetVersionEncoded}`, 'notification-worker'); worker.addEventListener('error', (event) => { console.error('worker error', event); }); diff --git a/web_src/js/index.js b/web_src/js/index.js index 0c786f96fbef2..28c60ab9fbbad 100644 --- a/web_src/js/index.js +++ b/web_src/js/index.js @@ -1,5 +1,6 @@ // bootstrap module must be the first one to be imported, it handles webpack lazy-loading and global errors import './bootstrap.js'; +import '../fomantic/build/semantic.js'; import {initRepoActivityTopAuthorsChart} from './components/RepoActivityTopAuthors.vue'; import {initScopedAccessTokenCategories} from './components/ScopedAccessTokenSelector.vue'; diff --git a/web_src/js/jquery.js b/web_src/js/jquery.js deleted file mode 100644 index 892e2763cbbfb..0000000000000 --- a/web_src/js/jquery.js +++ /dev/null @@ -1,3 +0,0 @@ -import $ from 'jquery'; - -window.$ = window.jQuery = $; diff --git a/web_src/js/utils.js b/web_src/js/utils.js index 4655b8eacc6ba..1b701e1c6a53f 100644 --- a/web_src/js/utils.js +++ b/web_src/js/utils.js @@ -11,16 +11,6 @@ export function extname(path = '') { return ext || ''; } -// join a list of path segments with slashes, ensuring no double slashes -export function joinPaths(...parts) { - let str = ''; - for (const part of parts) { - if (!part) continue; - str = !str ? part : `${str.replace(/\/$/, '')}/${part.replace(/^\//, '')}`; - } - return str; -} - // test whether a variable is an object export function isObject(obj) { return Object.prototype.toString.call(obj) === '[object Object]'; diff --git a/web_src/js/utils.test.js b/web_src/js/utils.test.js index 812ef3bedfdc0..5f60c9c30b75a 100644 --- a/web_src/js/utils.test.js +++ b/web_src/js/utils.test.js @@ -1,6 +1,6 @@ import {expect, test} from 'vitest'; import { - basename, extname, isObject, stripTags, joinPaths, parseIssueHref, + basename, extname, isObject, stripTags, parseIssueHref, parseUrl, translateMonth, translateDay, blobToDataURI, toAbsoluteUrl, encodeURLEncodedBase64, decodeURLEncodedBase64, } from './utils.js'; @@ -18,45 +18,6 @@ test('extname', () => { expect(extname('file.js')).toEqual('.js'); }); -test('joinPaths', () => { - expect(joinPaths('', '')).toEqual(''); - expect(joinPaths('', 'b')).toEqual('b'); - expect(joinPaths('', '/b')).toEqual('/b'); - expect(joinPaths('', '/b/')).toEqual('/b/'); - expect(joinPaths('a', '')).toEqual('a'); - expect(joinPaths('/a', '')).toEqual('/a'); - expect(joinPaths('/a/', '')).toEqual('/a/'); - expect(joinPaths('a', 'b')).toEqual('a/b'); - expect(joinPaths('a', '/b')).toEqual('a/b'); - expect(joinPaths('/a', '/b')).toEqual('/a/b'); - expect(joinPaths('/a', '/b')).toEqual('/a/b'); - expect(joinPaths('/a/', '/b')).toEqual('/a/b'); - expect(joinPaths('/a', '/b/')).toEqual('/a/b/'); - expect(joinPaths('/a/', '/b/')).toEqual('/a/b/'); - - expect(joinPaths('', '', '')).toEqual(''); - expect(joinPaths('', 'b', '')).toEqual('b'); - expect(joinPaths('', 'b', 'c')).toEqual('b/c'); - expect(joinPaths('', '', 'c')).toEqual('c'); - expect(joinPaths('', '/b', '/c')).toEqual('/b/c'); - expect(joinPaths('/a', '', '/c')).toEqual('/a/c'); - expect(joinPaths('/a', '/b', '')).toEqual('/a/b'); - - expect(joinPaths('', '/')).toEqual('/'); - expect(joinPaths('a', '/')).toEqual('a/'); - expect(joinPaths('', '/', '/')).toEqual('/'); - expect(joinPaths('/', '/')).toEqual('/'); - expect(joinPaths('/', '')).toEqual('/'); - expect(joinPaths('/', 'b')).toEqual('/b'); - expect(joinPaths('/', 'b/')).toEqual('/b/'); - expect(joinPaths('/', '', '/')).toEqual('/'); - expect(joinPaths('/', 'b', '/')).toEqual('/b/'); - expect(joinPaths('/', 'b/', '/')).toEqual('/b/'); - expect(joinPaths('a', '/', '/')).toEqual('a/'); - expect(joinPaths('/', '/', 'c')).toEqual('/c'); - expect(joinPaths('/', '/', 'c/')).toEqual('/c/'); -}); - test('isObject', () => { expect(isObject({})).toBeTruthy(); expect(isObject([])).toBeFalsy(); diff --git a/web_src/js/vendor/ays.js b/web_src/js/vendor/ays.js new file mode 100644 index 0000000000000..67711a0150733 --- /dev/null +++ b/web_src/js/vendor/ays.js @@ -0,0 +1,181 @@ +/* copy of https://github.com/codedance/jquery.AreYouSure/ made to work in strict mode */ +(function($) { + + $.fn.areYouSure = function(options) { + + var settings = $.extend( + { + 'message' : 'You have unsaved changes!', + 'dirtyClass' : 'dirty', + 'change' : null, + 'silent' : false, + 'addRemoveFieldsMarksDirty' : false, + 'fieldEvents' : 'change keyup propertychange input', + 'fieldSelector': ":input:not(input[type=submit]):not(input[type=button])" + }, options); + + var getValue = function($field) { + if ($field.hasClass('ays-ignore') + || $field.hasClass('aysIgnore') + || $field.attr('data-ays-ignore') + || $field.attr('name') === undefined) { + return null; + } + + if ($field.is(':disabled')) { + return 'ays-disabled'; + } + + var val; + var type = $field.attr('type'); + if ($field.is('select')) { + type = 'select'; + } + + switch (type) { + case 'checkbox': + case 'radio': + val = $field.is(':checked'); + break; + case 'select': + val = ''; + $field.find('option').each(function(o) { + var $option = $(this); + if ($option.is(':selected')) { + val += $option.val(); + } + }); + break; + default: + val = $field.val(); + } + + return val; + }; + + var storeOrigValue = function($field) { + $field.data('ays-orig', getValue($field)); + }; + + var checkForm = function(evt) { + + var isFieldDirty = function($field) { + var origValue = $field.data('ays-orig'); + if (undefined === origValue) { + return false; + } + return (getValue($field) != origValue); + }; + + var $form = ($(this).is('form')) + ? $(this) + : $(this).parents('form'); + + // Test on the target first as it's the most likely to be dirty + if (isFieldDirty($(evt.target))) { + setDirtyStatus($form, true); + return; + } + + const $fields = $form.find(settings.fieldSelector); + + if (settings.addRemoveFieldsMarksDirty) { + // Check if field count has changed + var origCount = $form.data("ays-orig-field-count"); + if (origCount != $fields.length) { + setDirtyStatus($form, true); + return; + } + } + + // Brute force - check each field + var isDirty = false; + $fields.each(function() { + var $field = $(this); + if (isFieldDirty($field)) { + isDirty = true; + return false; // break + } + }); + + setDirtyStatus($form, isDirty); + }; + + var initForm = function($form) { + var fields = $form.find(settings.fieldSelector); + $(fields).each(function() { storeOrigValue($(this)); }); + $(fields).unbind(settings.fieldEvents, checkForm); + $(fields).bind(settings.fieldEvents, checkForm); + $form.data("ays-orig-field-count", $(fields).length); + setDirtyStatus($form, false); + }; + + var setDirtyStatus = function($form, isDirty) { + var changed = isDirty != $form.hasClass(settings.dirtyClass); + $form.toggleClass(settings.dirtyClass, isDirty); + + // Fire change event if required + if (changed) { + if (settings.change) settings.change.call($form, $form); + + if (isDirty) $form.trigger('dirty.areYouSure', [$form]); + if (!isDirty) $form.trigger('clean.areYouSure', [$form]); + $form.trigger('change.areYouSure', [$form]); + } + }; + + var rescan = function() { + var $form = $(this); + var fields = $form.find(settings.fieldSelector); + $(fields).each(function() { + var $field = $(this); + if (!$field.data('ays-orig')) { + storeOrigValue($field); + $field.bind(settings.fieldEvents, checkForm); + } + }); + // Check for changes while we're here + $form.trigger('checkform.areYouSure'); + }; + + var reinitialize = function() { + initForm($(this)); + } + + if (!settings.silent && !window.aysUnloadSet) { + window.aysUnloadSet = true; + $(window).bind('beforeunload', function() { + const $dirtyForms = $("form").filter('.' + settings.dirtyClass); + if ($dirtyForms.length == 0) { + return; + } + // Prevent multiple prompts - seen on Chrome and IE + if (navigator.userAgent.toLowerCase().match(/msie|chrome/)) { + if (window.aysHasPrompted) { + return; + } + window.aysHasPrompted = true; + window.setTimeout(function() {window.aysHasPrompted = false;}, 900); + } + return settings.message; + }); + } + + return this.each(function(elem) { + if (!$(this).is('form')) { + return; + } + var $form = $(this); + + $form.submit(function() { + $form.removeClass(settings.dirtyClass); + }); + $form.bind('reset', function() { setDirtyStatus($form, false); }); + // Add a custom events + $form.bind('rescan.areYouSure', rescan); + $form.bind('reinitialize.areYouSure', reinitialize); + $form.bind('checkform.areYouSure', checkForm); + initForm($form); + }); + }; +})(jQuery); diff --git a/webpack.config.js b/webpack.config.js index 4dab5cfbaefb2..577dc7c88a55c 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -40,9 +40,8 @@ const filterCssImport = (url, ...args) => { const cssFile = args[1] || args[0]; // resourcePath is 2nd argument for url and 3rd for import const importedFile = url.replace(/[?#].+/, '').toLowerCase(); - if (cssFile.includes('fomantic')) { - if (/brand-icons/.test(importedFile)) return false; - if (/(eot|ttf|otf|woff|svg)$/.test(importedFile)) return false; + if (cssFile.includes('fomantic') && /(eot|ttf|otf|woff|svg)$/.test(importedFile)) { + return false; } if (cssFile.includes('katex') && /(ttf|woff)$/.test(importedFile)) { @@ -57,11 +56,7 @@ export default { mode: isProduction ? 'production' : 'development', entry: { index: [ - fileURLToPath(new URL('web_src/js/jquery.js', import.meta.url)), - fileURLToPath(new URL('web_src/fomantic/build/semantic.js', import.meta.url)), fileURLToPath(new URL('web_src/js/index.js', import.meta.url)), - fileURLToPath(new URL('node_modules/easymde/dist/easymde.min.css', import.meta.url)), - fileURLToPath(new URL('web_src/fomantic/build/semantic.css', import.meta.url)), fileURLToPath(new URL('web_src/css/index.css', import.meta.url)), ], webcomponents: [ @@ -84,13 +79,18 @@ export default { }, devtool: false, output: { - path: fileURLToPath(new URL('public', import.meta.url)), - filename: () => 'js/[name].js', + module: true, + publicPath: '', + path: fileURLToPath(new URL('public/static', import.meta.url)), + filename: () => '[name].js', chunkFilename: ({chunk}) => { const language = (/monaco.*languages?_.+?_(.+?)_/.exec(chunk.id) || [])[1]; - return `js/${language ? `monaco-language-${language.toLowerCase()}` : `[name]`}.[contenthash:8].js`; + return `${language ? `monaco-language-${language.toLowerCase()}` : `[name]`}.[contenthash:8].js`; }, }, + experiments: { + outputModule: true, + }, optimization: { minimize: isProduction, minimizer: [ @@ -154,14 +154,14 @@ export default { test: /\.(ttf|woff2?)$/, type: 'asset/resource', generator: { - filename: 'fonts/[name].[contenthash:8][ext]', + filename: '[name].[contenthash:8][ext]', } }, { test: /\.png$/i, type: 'asset/resource', generator: { - filename: 'img/webpack/[name].[contenthash:8][ext]', + filename: '[name].[contenthash:8][ext]', } }, ], @@ -173,17 +173,17 @@ export default { }), new VueLoaderPlugin(), new MiniCssExtractPlugin({ - filename: 'css/[name].css', - chunkFilename: 'css/[name].[contenthash:8].css', + filename: '[name].css', + chunkFilename: '[name].[contenthash:8].css', }), sourceMapEnabled && (new SourceMapDevToolPlugin({ filename: '[file].[contenthash:8].map', })), new MonacoWebpackPlugin({ - filename: 'js/monaco-[name].[contenthash:8].worker.js', + filename: 'monaco-[name].[contenthash:8].worker.js', }), isProduction ? new LicenseCheckerWebpackPlugin({ - outputFilename: 'js/licenses.txt', + outputFilename: 'licenses.txt', outputWriter: ({dependencies}) => { const line = '-'.repeat(80); const goJson = readFileSync('assets/go-licenses.json', 'utf8'); @@ -201,12 +201,11 @@ export default { }).join('\n'); }, override: { - 'jquery.are-you-sure@*': {licenseName: 'MIT'}, // https://github.com/codedance/jquery.AreYouSure/pull/147 'khroma@*': {licenseName: 'MIT'}, // https://github.com/fabiospampinato/khroma/pull/33 }, emitError: true, allow: '(Apache-2.0 OR BSD-2-Clause OR BSD-3-Clause OR MIT OR ISC OR CPAL-1.0 OR Unlicense OR EPL-1.0 OR EPL-2.0)', - }) : new AddAssetPlugin('js/licenses.txt', `Licenses are disabled during development`), + }) : new AddAssetPlugin('licenses.txt', `Licenses are disabled during development`), ], performance: { hints: false, @@ -232,10 +231,6 @@ export default { chunksSort: 'name', colors: true, entrypoints: false, - excludeAssets: [ - /^js\/monaco-language-.+\.js$/, - !isProduction && /^js\/licenses.txt$/, - ].filter(Boolean), groupAssetsByChunk: false, groupAssetsByEmitStatus: false, groupAssetsByInfo: false, From 564361e2a2b05ad5f70f2f648e08904e8d5e8529 Mon Sep 17 00:00:00 2001 From: silverwind Date: Tue, 18 Jul 2023 01:02:43 +0200 Subject: [PATCH 02/24] fix WEBPACK_DEST --- Makefile | 2 +- public/index.css | 0 public/index.js | 0 3 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 public/index.css delete mode 100644 public/index.js diff --git a/Makefile b/Makefile index 1e47ab3f28203..d284f1c487f11 100644 --- a/Makefile +++ b/Makefile @@ -116,7 +116,7 @@ FOMANTIC_WORK_DIR := web_src/fomantic WEBPACK_SOURCES := $(shell find web_src/js web_src/css -type f) WEBPACK_CONFIGS := webpack.config.js -WEBPACK_DEST := public/index.js public/index.css +WEBPACK_DEST := public/static/index.js public/static/index.css WEBPACK_DEST_ENTRIES := /public/static BINDATA_DEST := modules/public/bindata.go modules/options/bindata.go modules/templates/bindata.go diff --git a/public/index.css b/public/index.css deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/public/index.js b/public/index.js deleted file mode 100644 index e69de29bb2d1d..0000000000000 From 098a72c9c6cb43398f654fb0f75c380fe4069ad5 Mon Sep 17 00:00:00 2001 From: silverwind Date: Tue, 18 Jul 2023 01:21:35 +0200 Subject: [PATCH 03/24] fix WEBPACK_DEST_ENTRIES --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index d284f1c487f11..c23912e0e4912 100644 --- a/Makefile +++ b/Makefile @@ -117,7 +117,7 @@ FOMANTIC_WORK_DIR := web_src/fomantic WEBPACK_SOURCES := $(shell find web_src/js web_src/css -type f) WEBPACK_CONFIGS := webpack.config.js WEBPACK_DEST := public/static/index.js public/static/index.css -WEBPACK_DEST_ENTRIES := /public/static +WEBPACK_DEST_ENTRIES := public/static BINDATA_DEST := modules/public/bindata.go modules/options/bindata.go modules/templates/bindata.go BINDATA_HASH := $(addsuffix .hash,$(BINDATA_DEST)) From e42d45a5c96ea958cf4d38326531a5dbb22e7608 Mon Sep 17 00:00:00 2001 From: silverwind Date: Tue, 18 Jul 2023 01:23:04 +0200 Subject: [PATCH 04/24] move import --- web_src/css/index.css | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/web_src/css/index.css b/web_src/css/index.css index 9b841dde021c5..ec82b999c193a 100644 --- a/web_src/css/index.css +++ b/web_src/css/index.css @@ -1,4 +1,5 @@ @import "../fomantic/build/semantic.css"; +@import "easymde/dist/easymde.min.css"; @import "./modules/normalize.css"; @import "./modules/animations.css"; @@ -63,5 +64,3 @@ @import "./review.css"; @import "./actions.css"; @import "./helpers.css"; - -@import "easymde/dist/easymde.min.css"; From 67a46fd9cf5aa825f34efdfa4c09b32089b5d43d Mon Sep 17 00:00:00 2001 From: silverwind Date: Tue, 18 Jul 2023 02:31:48 +0200 Subject: [PATCH 05/24] Update web_src/js/bootstrap.js --- web_src/js/bootstrap.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web_src/js/bootstrap.js b/web_src/js/bootstrap.js index d70be7dfb0bb6..b1f9c5a2cd350 100644 --- a/web_src/js/bootstrap.js +++ b/web_src/js/bootstrap.js @@ -7,7 +7,7 @@ window.$ = window.jQuery = $; // This sets up the URL prefix used in webpack's chunk loading. // This file must be imported before any lazy-loading is being attempted. -__webpack_public_path__ = `${window.config?.assetUrlPrefix}/static/`; +__webpack_public_path__ = `${window.config?.assetUrlPrefix ?? '/assets'}/static/`; export function showGlobalErrorMessage(msg) { const pageContent = document.querySelector('.page-content'); From f4b9927a275f40ca26534e3bd6587981fecd5c87 Mon Sep 17 00:00:00 2001 From: silverwind Date: Tue, 18 Jul 2023 23:55:34 +0200 Subject: [PATCH 06/24] devtest fixes --- templates/devtest/fomantic-modal.tmpl | 13 ++----------- templates/devtest/gitea-ui.tmpl | 9 --------- web_src/css/standalone/devtest.css | 4 ++++ web_src/js/bootstrap.js | 4 ---- web_src/js/index.js | 1 + web_src/js/jquery.js | 3 +++ web_src/js/standalone/devtest.js | 24 +++++++++++++++++++++--- 7 files changed, 31 insertions(+), 27 deletions(-) create mode 100644 web_src/js/jquery.js diff --git a/templates/devtest/fomantic-modal.tmpl b/templates/devtest/fomantic-modal.tmpl index 799bab7594e2b..f5d89fbe6eeae 100644 --- a/templates/devtest/fomantic-modal.tmpl +++ b/templates/devtest/fomantic-modal.tmpl @@ -1,4 +1,5 @@ {{template "base/head" .}} +
{{template "base/alert" .}} @@ -47,16 +48,6 @@
- - + {{template "base/footer" .}} diff --git a/templates/devtest/gitea-ui.tmpl b/templates/devtest/gitea-ui.tmpl index 4835843e42ea2..443ce5bbc20b8 100644 --- a/templates/devtest/gitea-ui.tmpl +++ b/templates/devtest/gitea-ui.tmpl @@ -67,15 +67,6 @@ - diff --git a/web_src/css/standalone/devtest.css b/web_src/css/standalone/devtest.css index a7b00e1e56181..de6db14768988 100644 --- a/web_src/css/standalone/devtest.css +++ b/web_src/css/standalone/devtest.css @@ -14,3 +14,7 @@ h1, h2 { margin: 0; padding: 10px 0; } + +.modal-buttons button { + margin: 5px; +} diff --git a/web_src/js/bootstrap.js b/web_src/js/bootstrap.js index b1f9c5a2cd350..796939d73f1e1 100644 --- a/web_src/js/bootstrap.js +++ b/web_src/js/bootstrap.js @@ -1,7 +1,3 @@ -import $ from 'jquery'; - -window.$ = window.jQuery = $; - // DO NOT IMPORT window.config HERE! // to make sure the error handler always works, we should never import `window.config`, because some user's custom template breaks it. diff --git a/web_src/js/index.js b/web_src/js/index.js index 28c60ab9fbbad..8319454813062 100644 --- a/web_src/js/index.js +++ b/web_src/js/index.js @@ -1,5 +1,6 @@ // bootstrap module must be the first one to be imported, it handles webpack lazy-loading and global errors import './bootstrap.js'; +import './jquery.js'; import '../fomantic/build/semantic.js'; import {initRepoActivityTopAuthorsChart} from './components/RepoActivityTopAuthors.vue'; diff --git a/web_src/js/jquery.js b/web_src/js/jquery.js new file mode 100644 index 0000000000000..892e2763cbbfb --- /dev/null +++ b/web_src/js/jquery.js @@ -0,0 +1,3 @@ +import $ from 'jquery'; + +window.$ = window.jQuery = $; diff --git a/web_src/js/standalone/devtest.js b/web_src/js/standalone/devtest.js index d0ca511c0f36a..33940efbb0e11 100644 --- a/web_src/js/standalone/devtest.js +++ b/web_src/js/standalone/devtest.js @@ -1,11 +1,29 @@ +import '../jquery.js'; +import '../../fomantic/build/semantic.js'; +import $ from 'jquery'; import {showInfoToast, showWarningToast, showErrorToast} from '../modules/toast.js'; -document.getElementById('info-toast').addEventListener('click', () => { +document.getElementById('info-toast')?.addEventListener('click', () => { showInfoToast('success 😀'); }); -document.getElementById('warning-toast').addEventListener('click', () => { +document.getElementById('warning-toast')?.addEventListener('click', () => { showWarningToast('warning 😐'); }); -document.getElementById('error-toast').addEventListener('click', () => { +document.getElementById('error-toast')?.addEventListener('click', () => { showErrorToast('error 🙁'); }); + +const $buttons = $('#devtest-button-samples').find('button.ui'); + +const $buttonStyles = $('input[name*="button-style"]'); +$buttonStyles.on('click', () => $buttonStyles.map((_, el) => $buttons.toggleClass(el.value, el.checked))); + +const $buttonStates = $('input[name*="button-state"]'); +$buttonStates.on('click', () => $buttonStates.map((_, el) => $buttons.prop(el.value, el.checked))); + +for (const el of $('.ui.modal')) { + const $btn = $('