forgejo/templates/base/head_script.tmpl

50 lines
2.3 KiB
Handlebars
Raw Normal View History

{{/*
==== DO NOT EDIT ====
If you are customizing Gitea, please do not change this file.
If you introduce mistakes in it, Gitea JavaScript code wouldn't run correctly.
*/}}
<script>
window.addEventListener('error', function(e) {window._globalHandlerErrors=window._globalHandlerErrors||[]; window._globalHandlerErrors.push(e);});
window.config = {
appUrl: '{{AppUrl}}',
appSubUrl: '{{AppSubUrl}}',
assetVersionEncoded: encodeURIComponent('{{AssetVersion}}'), // will be used in URL construction directly
assetUrlPrefix: '{{AssetUrlPrefix}}',
runModeIsProd: {{.RunModeIsProd}},
customEmojis: {{CustomEmojis}},
useServiceWorker: {{UseServiceWorker}},
csrfToken: '{{.CsrfToken}}',
pageData: {{.PageData}},
requireTribute: {{.RequireTribute}},
notificationSettings: {{NotificationSettings}}, {{/*a map provided by NewFuncMap in helper.go*/}}
enableTimeTracking: {{EnableTimetracking}},
{{if .RequireTribute}}
tributeValues: Array.from(new Map([
{{range .Participants}}
['{{.Name}}', {key: '{{.Name}} {{.FullName}}', value: '{{.Name}}',
Add context cache as a request level cache (#22294) To avoid duplicated load of the same data in an HTTP request, we can set a context cache to do that. i.e. Some pages may load a user from a database with the same id in different areas on the same page. But the code is hidden in two different deep logic. How should we share the user? As a result of this PR, now if both entry functions accept `context.Context` as the first parameter and we just need to refactor `GetUserByID` to reuse the user from the context cache. Then it will not be loaded twice on an HTTP request. But of course, sometimes we would like to reload an object from the database, that's why `RemoveContextData` is also exposed. The core context cache is here. It defines a new context ```go type cacheContext struct { ctx context.Context data map[any]map[any]any lock sync.RWMutex } var cacheContextKey = struct{}{} func WithCacheContext(ctx context.Context) context.Context { return context.WithValue(ctx, cacheContextKey, &cacheContext{ ctx: ctx, data: make(map[any]map[any]any), }) } ``` Then you can use the below 4 methods to read/write/del the data within the same context. ```go func GetContextData(ctx context.Context, tp, key any) any func SetContextData(ctx context.Context, tp, key, value any) func RemoveContextData(ctx context.Context, tp, key any) func GetWithContextCache[T any](ctx context.Context, cacheGroupKey string, cacheTargetID any, f func() (T, error)) (T, error) ``` Then let's take a look at how `system.GetString` implement it. ```go func GetSetting(ctx context.Context, key string) (string, error) { return cache.GetWithContextCache(ctx, contextCacheKey, key, func() (string, error) { return cache.GetString(genSettingCacheKey(key), func() (string, error) { res, err := GetSettingNoCache(ctx, key) if err != nil { return "", err } return res.SettingValue, nil }) }) } ``` First, it will check if context data include the setting object with the key. If not, it will query from the global cache which may be memory or a Redis cache. If not, it will get the object from the database. In the end, if the object gets from the global cache or database, it will be set into the context cache. An object stored in the context cache will only be destroyed after the context disappeared.
2023-02-15 22:37:34 +09:00
name: '{{.Name}}', fullname: '{{.FullName}}', avatar: '{{.AvatarLink $.Context}}'}],
{{end}}
{{range .Assignees}}
['{{.Name}}', {key: '{{.Name}} {{.FullName}}', value: '{{.Name}}',
Add context cache as a request level cache (#22294) To avoid duplicated load of the same data in an HTTP request, we can set a context cache to do that. i.e. Some pages may load a user from a database with the same id in different areas on the same page. But the code is hidden in two different deep logic. How should we share the user? As a result of this PR, now if both entry functions accept `context.Context` as the first parameter and we just need to refactor `GetUserByID` to reuse the user from the context cache. Then it will not be loaded twice on an HTTP request. But of course, sometimes we would like to reload an object from the database, that's why `RemoveContextData` is also exposed. The core context cache is here. It defines a new context ```go type cacheContext struct { ctx context.Context data map[any]map[any]any lock sync.RWMutex } var cacheContextKey = struct{}{} func WithCacheContext(ctx context.Context) context.Context { return context.WithValue(ctx, cacheContextKey, &cacheContext{ ctx: ctx, data: make(map[any]map[any]any), }) } ``` Then you can use the below 4 methods to read/write/del the data within the same context. ```go func GetContextData(ctx context.Context, tp, key any) any func SetContextData(ctx context.Context, tp, key, value any) func RemoveContextData(ctx context.Context, tp, key any) func GetWithContextCache[T any](ctx context.Context, cacheGroupKey string, cacheTargetID any, f func() (T, error)) (T, error) ``` Then let's take a look at how `system.GetString` implement it. ```go func GetSetting(ctx context.Context, key string) (string, error) { return cache.GetWithContextCache(ctx, contextCacheKey, key, func() (string, error) { return cache.GetString(genSettingCacheKey(key), func() (string, error) { res, err := GetSettingNoCache(ctx, key) if err != nil { return "", err } return res.SettingValue, nil }) }) } ``` First, it will check if context data include the setting object with the key. If not, it will query from the global cache which may be memory or a Redis cache. If not, it will get the object from the database. In the end, if the object gets from the global cache or database, it will be set into the context cache. An object stored in the context cache will only be destroyed after the context disappeared.
2023-02-15 22:37:34 +09:00
name: '{{.Name}}', fullname: '{{.FullName}}', avatar: '{{.AvatarLink $.Context}}'}],
{{end}}
{{range .MentionableTeams}}
['{{$.MentionableTeamsOrg}}/{{.Name}}', {key: '{{$.MentionableTeamsOrg}}/{{.Name}}', value: '{{$.MentionableTeamsOrg}}/{{.Name}}',
name: '{{$.MentionableTeamsOrg}}/{{.Name}}', avatar: '{{$.MentionableTeamsOrgAvatar}}'}],
{{end}}
]).values()),
{{end}}
mermaidMaxSourceCharacters: {{MermaidMaxSourceCharacters}},
{{/* this global i18n object should only contain general texts. for specialized texts, it should be provided inside the related modules by: (1) API response (2) HTML data-attribute (3) PageData */}}
i18n: {
copy_success: '{{.locale.Tr "copy_success"}}',
copy_error: '{{.locale.Tr "copy_error"}}',
error_occurred: '{{.locale.Tr "error.occurred"}}',
network_error: '{{.locale.Tr "error.network_error"}}',
},
};
{{/* 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 || {};
</script>
Introduce customized HTML elements, fix incorrect AppUrl usages in templates (#22861) This PR follows: * #21986 * #22831 This PR also introduce customized HTML elements, which would also help problems like: * #17760 * #21429 * #21440 With customized HTML elements, there won't be any load-search-replace operations, and it can avoid page flicking (which @silverwind cares a lot). Browser support: https://developer.mozilla.org/en-US/docs/Web/API/Window/customElements # FAQ ## Why the component has the prefix? As usual, I would strongly suggest to add prefixes for our own/private names. The dedicated prefix will avoid conflicts in the future, and it makes it easier to introduce various 3rd components, like GitHub's `relative-time` component. If there is no prefix, it's impossible to introduce another public component with the same name in the future. ## Why the `custcomp.js` is loaded before HTML body? The `index.js` is after HTML body. Customized components must be registered before the content loading. Otherwise there would be still some flicking. `custcomp.js` should have its own dependencies and should be very light, so it won't affect the page loading time too much. ## Why use `data-url` attribute but not use the `textContent`? According to the standard, the `connectedCallback` occurs on the tag-opening moment. The element's children are not ready yet. ## Why not use `{{.GuessCurrentOrigin $.ctx ...}}` to let backend decide the absolute URL? It's difficult for backend to guess the correct protocol(scheme) correctly with zero configuration. Generating the absolute URL from frontend can guarantee that the URL is 100% correct -- since the user is visiting it. # Screenshot <details> ![image](https://user-images.githubusercontent.com/2114189/218256757-a267c8ba-3108-4755-9ae5-329f1b08f615.png) </details>
2023-02-17 23:02:20 +09:00
<script src="{{AssetUrlPrefix}}/js/webcomponents.js?v={{AssetVersion}}"></script>