Compare commits
9 Commits
ed37451d81
...
feat/devco
| Author | SHA1 | Date | |
|---|---|---|---|
| 416c954119 | |||
| e4baca8811 | |||
| a1ea929a8b | |||
| 85d3022496 | |||
| ebd7d0753c | |||
| 98e8fec2d6 | |||
| 0333d323e0 | |||
| 51e4189dc9 | |||
| 8115eb4b6f |
@@ -47,9 +47,37 @@ func DefaultOpenWithEditorApps() OpenWithEditorAppsType {
|
||||
}
|
||||
}
|
||||
|
||||
// DevContainerEditorApp represents a configured IDE for DevContainer
|
||||
type DevContainerEditorApp struct {
|
||||
DisplayName string // Display name, e.g. "VSCode"
|
||||
Protocol string // Protocol prefix, e.g. "vscode"
|
||||
}
|
||||
|
||||
type DevContainerEditorAppsType []DevContainerEditorApp
|
||||
|
||||
// ToTextareaString converts the configuration to textarea format
|
||||
func (t DevContainerEditorAppsType) ToTextareaString() string {
|
||||
ret := ""
|
||||
for _, app := range t {
|
||||
ret += app.DisplayName + " = " + app.Protocol + "\n"
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// DefaultDevContainerEditorApps returns the default DevContainer IDE configuration
|
||||
func DefaultDevContainerEditorApps() DevContainerEditorAppsType {
|
||||
return DevContainerEditorAppsType{
|
||||
{DisplayName: "VSCode", Protocol: "vscode"},
|
||||
{DisplayName: "Cursor", Protocol: "cursor"},
|
||||
{DisplayName: "Windsurf", Protocol: "windsurf"},
|
||||
{DisplayName: "Trae", Protocol: "trae"},
|
||||
}
|
||||
}
|
||||
|
||||
type RepositoryStruct struct {
|
||||
OpenWithEditorApps *config.Value[OpenWithEditorAppsType]
|
||||
GitGuideRemoteName *config.Value[string]
|
||||
OpenWithEditorApps *config.Value[OpenWithEditorAppsType]
|
||||
DevContainerEditorApps *config.Value[DevContainerEditorAppsType]
|
||||
GitGuideRemoteName *config.Value[string]
|
||||
}
|
||||
|
||||
type ConfigStruct struct {
|
||||
@@ -70,8 +98,9 @@ func initDefaultConfig() {
|
||||
EnableFederatedAvatar: config.ValueJSON[bool]("picture.enable_federated_avatar").WithFileConfig(config.CfgSecKey{Sec: "picture", Key: "ENABLE_FEDERATED_AVATAR"}),
|
||||
},
|
||||
Repository: &RepositoryStruct{
|
||||
OpenWithEditorApps: config.ValueJSON[OpenWithEditorAppsType]("repository.open-with.editor-apps"),
|
||||
GitGuideRemoteName: config.ValueJSON[string]("repository.git-guide-remote-name").WithDefault("origin"),
|
||||
OpenWithEditorApps: config.ValueJSON[OpenWithEditorAppsType]("repository.open-with.editor-apps"),
|
||||
DevContainerEditorApps: config.ValueJSON[DevContainerEditorAppsType]("repository.devcontainer.editor-apps").WithDefault(DefaultDevContainerEditorApps()),
|
||||
GitGuideRemoteName: config.ValueJSON[string]("repository.git-guide-remote-name").WithDefault("origin"),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,6 +122,8 @@ var (
|
||||
ManifestData string
|
||||
|
||||
BeianNumber string // 网站备案号, e.g. 苏ICP备88888888888号-1
|
||||
ParentDomain string // 父域名,用于获取上级DevStar的相关服务 PARENT_DOMAIN
|
||||
ParentAccessToken string // 父域名访问令牌,用于获取上级DevStar的相关服务 PARENT_ACCESS_TOKEN
|
||||
|
||||
)
|
||||
|
||||
@@ -192,6 +194,8 @@ func loadServerFrom(rootCfg ConfigProvider) {
|
||||
HTTPAddr = sec.Key("HTTP_ADDR").MustString("0.0.0.0")
|
||||
HTTPPort = sec.Key("HTTP_PORT").MustString("3000")
|
||||
BeianNumber = sec.Key("BEIAN_NUMBER").MustString("")
|
||||
ParentDomain = sec.Key("PARENT_DOMAIN").MustString("https://devstar.cn")
|
||||
ParentAccessToken = sec.Key("PARENT_ACCESS_TOKEN").MustString("439ffb6e2cce9ecb4568a5c54750ef290831d2ef")
|
||||
|
||||
// DEPRECATED should not be removed because users maybe upgrade from lower version to the latest version
|
||||
// if these are removed, the warning will not be shown
|
||||
|
||||
@@ -161,6 +161,12 @@ func NewFuncMap() template.FuncMap {
|
||||
"BeianNumber": func() string {
|
||||
return setting.BeianNumber
|
||||
},
|
||||
"ParentDomain": func() string {
|
||||
return setting.ParentDomain
|
||||
},
|
||||
"ParentAccessToken": func() string {
|
||||
return setting.ParentAccessToken
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3596,6 +3596,8 @@ config.disable_gravatar = Disable Gravatar
|
||||
config.enable_federated_avatar = Enable Federated Avatars
|
||||
config.open_with_editor_app_help = The "Open with" editors for the clone menu. If left empty, the default will be used. Expand to see the default.
|
||||
config.git_guide_remote_name = Repository remote name for git commands in the guide
|
||||
config.devcontainer_editor_apps = DevContainer Editor Apps
|
||||
config.devcontainer_editor_app_help = Configure which AI IDEs appear in the devcontainer "Open with" menu. If left empty, the default will be used. Expand to see the default.
|
||||
|
||||
config.git_config = Git Configuration
|
||||
config.git_disable_diff_highlight = Disable Diff Syntax Highlight
|
||||
|
||||
@@ -3589,6 +3589,8 @@ config.disable_gravatar=禁用 Gravatar 头像
|
||||
config.enable_federated_avatar=启用 Federated 头像
|
||||
config.open_with_editor_app_help=用于克隆菜单的编辑器。如果为空将使用默认值。展开可以查看默认值。
|
||||
config.git_guide_remote_name=指南中 git 命令使用的仓库远程名称
|
||||
config.devcontainer_editor_apps=DevContainer 编辑器应用
|
||||
config.devcontainer_editor_app_help=配置 DevContainer "打开方式" 菜单中显示的 AI IDE。如果为空将使用默认值。展开可以查看默认值。
|
||||
|
||||
config.git_config=Git 配置
|
||||
config.git_disable_diff_highlight=禁用差异对比语法高亮
|
||||
|
||||
@@ -197,6 +197,7 @@ func ConfigSettings(ctx *context.Context) {
|
||||
ctx.Data["PageIsAdminConfig"] = true
|
||||
ctx.Data["PageIsAdminConfigSettings"] = true
|
||||
ctx.Data["DefaultOpenWithEditorAppsString"] = setting.DefaultOpenWithEditorApps().ToTextareaString()
|
||||
ctx.Data["DefaultDevContainerEditorAppsString"] = setting.DefaultDevContainerEditorApps().ToTextareaString()
|
||||
ctx.HTML(http.StatusOK, tplConfigSettings)
|
||||
}
|
||||
|
||||
@@ -236,10 +237,11 @@ func ChangeConfig(ctx *context.Context) {
|
||||
return json.Marshal(openWithEditorApps)
|
||||
}
|
||||
marshallers := map[string]func(string) ([]byte, error){
|
||||
cfg.Picture.DisableGravatar.DynKey(): marshalBool,
|
||||
cfg.Picture.EnableFederatedAvatar.DynKey(): marshalBool,
|
||||
cfg.Repository.OpenWithEditorApps.DynKey(): marshalOpenWithApps,
|
||||
cfg.Repository.GitGuideRemoteName.DynKey(): marshalString(cfg.Repository.GitGuideRemoteName.DefaultValue()),
|
||||
cfg.Picture.DisableGravatar.DynKey(): marshalBool,
|
||||
cfg.Picture.EnableFederatedAvatar.DynKey(): marshalBool,
|
||||
cfg.Repository.OpenWithEditorApps.DynKey(): marshalOpenWithApps,
|
||||
cfg.Repository.DevContainerEditorApps.DynKey(): marshalOpenWithApps,
|
||||
cfg.Repository.GitGuideRemoteName.DynKey(): marshalString(cfg.Repository.GitGuideRemoteName.DefaultValue()),
|
||||
}
|
||||
|
||||
_ = ctx.Req.ParseForm()
|
||||
|
||||
@@ -159,10 +159,14 @@ func GetDevContainerDetails(ctx *context.Context) {
|
||||
}
|
||||
terminalURL, err := devcontainer_service.Get_IDE_TerminalURL(ctx, ctx.Doer, ctx.Repo)
|
||||
if err == nil {
|
||||
ctx.Data["VSCodeUrl"] = "vscode" + terminalURL + "&cmd=code"
|
||||
ctx.Data["CursorUrl"] = "cursor" + terminalURL + "&cmd=cursor"
|
||||
ctx.Data["WindsurfUrl"] = "windsurf" + terminalURL + "&cmd=windsurf"
|
||||
ctx.Data["TraeUrl"] = "trae" + terminalURL + "&cmd=trae"
|
||||
// Get configured IDE apps dynamically
|
||||
devContainerApps := setting.Config().Repository.DevContainerEditorApps.Value(ctx)
|
||||
ideURLs := make(map[string]string)
|
||||
for _, app := range devContainerApps {
|
||||
url := app.Protocol + terminalURL
|
||||
ideURLs[app.DisplayName] = url
|
||||
}
|
||||
ctx.Data["DevContainerIDEs"] = ideURLs
|
||||
}
|
||||
}
|
||||
// 3. 携带数据渲染页面,返回
|
||||
@@ -214,7 +218,7 @@ func GetDevContainerStatus(ctx *context.Context) {
|
||||
log.Info("%v\n", err)
|
||||
}
|
||||
|
||||
var vscodeUrl, cursorUrl, windsurfUrl, traeUrl string
|
||||
ideURLs := make(map[string]string)
|
||||
// 增加对 ctx.Doer、ctx.Repo、ctx.Repo.Repository 的检查,避免出现空指针异常
|
||||
// 只在第一次状态变为 "5" 时生成 URL,避免频繁调用导致 token 被删除,随 Session 过期(默认 24 小时)
|
||||
// 通过检查 session 中是否已有 terminal_url 来判断是否是第一次
|
||||
@@ -222,40 +226,31 @@ func GetDevContainerStatus(ctx *context.Context) {
|
||||
// 检查 session 中是否已有缓存的 URL
|
||||
cachedUrls := ctx.Session.Get("terminal_urls")
|
||||
if cachedUrls == nil {
|
||||
// 第一次状态为 "4",生成 URL 并缓存
|
||||
// 第一次状态为 "5",生成 URL 并缓存
|
||||
terminalURL, err := devcontainer_service.Get_IDE_TerminalURL(ctx, ctx.Doer, ctx.Repo)
|
||||
if err == nil {
|
||||
vscodeUrl = "vscode" + terminalURL + "&cmd=code"
|
||||
cursorUrl = "cursor" + terminalURL + "&cmd=cursor"
|
||||
windsurfUrl = "windsurf" + terminalURL + "&cmd=windsurf"
|
||||
traeUrl = "trae" + terminalURL + "&cmd=trae"
|
||||
// Get configured IDE apps dynamically
|
||||
devContainerApps := setting.Config().Repository.DevContainerEditorApps.Value(ctx)
|
||||
for _, app := range devContainerApps {
|
||||
url := app.Protocol + terminalURL
|
||||
ideURLs[app.DisplayName] = url
|
||||
}
|
||||
// 缓存 URL 到 session
|
||||
ctx.Session.Set("terminal_urls", map[string]string{
|
||||
"vscodeUrl": vscodeUrl,
|
||||
"cursorUrl": cursorUrl,
|
||||
"windsurfUrl": windsurfUrl,
|
||||
"traeUrl": traeUrl,
|
||||
})
|
||||
ctx.Session.Set("terminal_urls", ideURLs)
|
||||
}
|
||||
} else {
|
||||
// 使用缓存的 URL
|
||||
urls := cachedUrls.(map[string]string)
|
||||
vscodeUrl = urls["vscodeUrl"]
|
||||
cursorUrl = urls["cursorUrl"]
|
||||
windsurfUrl = urls["windsurfUrl"]
|
||||
traeUrl = urls["traeUrl"]
|
||||
ideURLs = urls
|
||||
}
|
||||
} else {
|
||||
// 状态不是 "4" 或 ctx.Doer 为 nil,清除缓存的 URL
|
||||
// 状态不是 "5" 或 ctx.Doer 为 nil,清除缓存的 URL
|
||||
ctx.Session.Delete("terminal_urls")
|
||||
}
|
||||
|
||||
ctx.JSON(http.StatusOK, map[string]string{
|
||||
"status": realTimeStatus,
|
||||
"vscodeUrl": vscodeUrl,
|
||||
"cursorUrl": cursorUrl,
|
||||
"windsurfUrl": windsurfUrl,
|
||||
"traeUrl": traeUrl,
|
||||
ctx.JSON(http.StatusOK, map[string]any{
|
||||
"status": realTimeStatus,
|
||||
"ideURLs": ideURLs,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -129,7 +129,7 @@ func Variables(ctx *context.Context) {
|
||||
tagsJSONStr = "[]"
|
||||
}
|
||||
// 创建一个新的请求
|
||||
req, err := http.NewRequest("GET", "http://devstar.cn/variables/export", nil)
|
||||
req, err := http.NewRequest("GET", setting.ParentDomain + "/variables/export", nil)
|
||||
if err != nil {
|
||||
ctx.Data["DevstarVariables"] = []*devcontainer_model.DevcontainerVariable{}
|
||||
} else {
|
||||
@@ -237,7 +237,7 @@ func ScriptCreate(ctx *context.Context) {
|
||||
}
|
||||
if !exists {
|
||||
// 创建一个新的请求来获取devstar变量
|
||||
req, err := http.NewRequest("GET", "http://devstar.cn/variables/export", nil)
|
||||
req, err := http.NewRequest("GET", setting.ParentDomain + "/variables/export", nil)
|
||||
if err != nil {
|
||||
log.Error("Failed to create request for devstar variables: %v", err)
|
||||
ctx.JSONError(ctx.Tr("actions.variables.creation.failed"))
|
||||
|
||||
@@ -1134,7 +1134,7 @@ func Get_IDE_TerminalURL(ctx *gitea_context.Context, doer *user.User, repo *gite
|
||||
"&username=" + doer.Name +
|
||||
"&path=" + fullWorkPath +
|
||||
"&access_token=" + access_token +
|
||||
"&devstar_username=" + repo.Repository.OwnerName +
|
||||
"&devstar_username=" + doer.Name +
|
||||
"&devstar_domain=" + setting.AppURL
|
||||
|
||||
// 添加 forwardPorts 参数(如果存在)
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
{{template "admin/layout_head" (dict "ctxData" . "pageClass" "admin config")}}
|
||||
<!-- 自定义logo upload -->
|
||||
<h4 class="ui top attached header">
|
||||
{{ctx.Locale.Tr "admin.config.app_logo_config"}}
|
||||
|
||||
@@ -21,6 +21,18 @@
|
||||
<input type="hidden" name="key" value="{{$cfg.DynKey}}">
|
||||
<input name="value" value="{{$cfg.Value ctx}}" placeholder="{{$cfg.DefaultValue}}" maxlength="100" dir="auto" required pattern="^[A-Za-z0-9][\-_A-Za-z0-9]*$">
|
||||
</div>
|
||||
<div class="field tw-mt-4">
|
||||
<label>{{ctx.Locale.Tr "admin.config.devcontainer_editor_apps"}}</label>
|
||||
<details>
|
||||
<summary>{{ctx.Locale.Tr "admin.config.devcontainer_editor_app_help"}}</summary>
|
||||
<pre class="tw-px-4">{{.DefaultDevContainerEditorAppsString}}</pre>
|
||||
</details>
|
||||
</div>
|
||||
<div class="field">
|
||||
{{$cfg = .SystemConfig.Repository.DevContainerEditorApps}}
|
||||
<input type="hidden" name="key" value="{{$cfg.DynKey}}">
|
||||
<textarea name="value" rows="6" placeholder="VSCode = vscode Cursor = cursor">{{($cfg.Value ctx).ToTextareaString}}</textarea>
|
||||
</div>
|
||||
<div class="field">
|
||||
<button class="ui primary button">{{ctx.Locale.Tr "save"}}</button>
|
||||
</div>
|
||||
|
||||
@@ -57,14 +57,12 @@
|
||||
{{if .isAdmin}}
|
||||
<div style=" display: none;" id="updateContainer" class="item"><a class="flex-text-inline" style="color:black; cursor:pointer; " href="#" onclick="if(typeof openSaveModal === 'function') { openSaveModal('{{.Repository.Link}}', '{{.Repository.Name}}'); return false; }">{{svg "octicon-database"}}{{ctx.Locale.Tr "repo.dev_container_control.update"}}</a></div>
|
||||
{{end}}
|
||||
|
||||
<div style=" display: none;" id="webTerminal" class="item"><a class="flex-text-inline" style="color:black; " href="{{.WebSSHUrl}}" target="_blank">{{svg "octicon-code" 14}}open with WebTerminal</a></div>
|
||||
<div style=" display: none;" id="vsTerminal" class="item"><a class="flex-text-inline" style="color:black; " onclick="window.location.href = '{{.VSCodeUrl}}'">{{svg "octicon-code" 14}}open with VSCode</a ></div>
|
||||
<div style=" display: none;" id="cursorTerminal" class="item"><a class="flex-text-inline" style="color:black; " onclick="window.location.href = '{{.CursorUrl}}'">{{svg "octicon-code" 14}}open with Cursor</a ></div>
|
||||
<div style=" display: none;" id="windsurfTerminal" class="item"><a class="flex-text-inline" style="color:black;" onclick="window.location.href = '{{.WindsurfUrl}}'">{{svg "octicon-code" 14}}open with Windsurf</a ></div>
|
||||
<div style=" display: none;" id="traeTerminal" class="item"><a class="flex-text-inline" style="color:black;" onclick="window.location.href = '{{.TraeUrl}}'">{{svg "octicon-code" 14}}open with Trae</a ></div>
|
||||
|
||||
|
||||
<div style=" display: none;" id="webTerminal" class="item"><a class="flex-text-inline" style="color:black; " href="{{.WebSSHUrl}}" target="_blank">{{svg "octicon-code" 14}}open with WebTerminal</a></div>
|
||||
{{range $name, $url := .DevContainerIDEs}}
|
||||
<div style=" display: none;" id="{{$name}}Terminal" class="item"><a class="flex-text-inline" style="color:black;" onclick="window.location.href = '{{$url}}'">{{svg "octicon-code" 14}}open with {{$name}}</a></div>
|
||||
{{end}}
|
||||
|
||||
{{end}}
|
||||
{{if .ValidateDevContainerConfiguration}}
|
||||
<div style=" display: none;" id="createContainer" class="item">
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -15,13 +15,12 @@ function initDevContainerDetails() {
|
||||
const restartContainer = document.getElementById('restartContainer');
|
||||
const stopContainer = document.getElementById('stopContainer');
|
||||
const webTerminal = document.getElementById('webTerminal');
|
||||
const vsTerminal = document.getElementById('vsTerminal');
|
||||
const cursorTerminal = document.getElementById('cursorTerminal');
|
||||
const windsurfTerminal = document.getElementById('windsurfTerminal');
|
||||
const traeTerminal = document.getElementById('traeTerminal');
|
||||
const webTerminalContainer = document.getElementById('webTerminalContainer');
|
||||
const loadingElement = document.getElementById('loading');
|
||||
|
||||
// Dynamically get all IDE terminal buttons
|
||||
const ideTerminals = document.querySelectorAll('[id$="Terminal"]:not(#webTerminal)');
|
||||
|
||||
function concealElement() {
|
||||
if (createContainer) createContainer.style.display = 'none';
|
||||
if (deleteContainer) deleteContainer.style.display = 'none';
|
||||
@@ -29,10 +28,10 @@ function initDevContainerDetails() {
|
||||
if (restartContainer) restartContainer.style.display = 'none';
|
||||
if (stopContainer) stopContainer.style.display = 'none';
|
||||
if (webTerminal) webTerminal.style.display = 'none';
|
||||
if (vsTerminal) vsTerminal.style.display = 'none';
|
||||
if (cursorTerminal) cursorTerminal.style.display = 'none';
|
||||
if (windsurfTerminal) windsurfTerminal.style.display = 'none';
|
||||
if (traeTerminal) traeTerminal.style.display = 'none';
|
||||
// Hide all IDE terminals
|
||||
ideTerminals.forEach((terminal) => {
|
||||
(terminal as HTMLElement).style.display = 'none';
|
||||
});
|
||||
if (webTerminalContainer) webTerminalContainer.style.display = 'none';
|
||||
}
|
||||
|
||||
@@ -42,10 +41,10 @@ function initDevContainerDetails() {
|
||||
if (restartContainer) restartContainer.style.display = 'block';
|
||||
if (stopContainer) stopContainer.style.display = 'block';
|
||||
if (webTerminal) webTerminal.style.display = 'block';
|
||||
if (vsTerminal) vsTerminal.style.display = 'block';
|
||||
if (cursorTerminal) cursorTerminal.style.display = 'block';
|
||||
if (windsurfTerminal) windsurfTerminal.style.display = 'block';
|
||||
if (traeTerminal) traeTerminal.style.display = 'block';
|
||||
// Show all IDE terminals
|
||||
ideTerminals.forEach((terminal) => {
|
||||
(terminal as HTMLElement).style.display = 'block';
|
||||
});
|
||||
if (webTerminalContainer) webTerminalContainer.style.display = 'block';
|
||||
}
|
||||
|
||||
@@ -81,21 +80,17 @@ function initDevContainerDetails() {
|
||||
if (loadingElement) loadingElement.style.display = 'none';
|
||||
if (restartContainer) restartContainer.style.display = 'none';
|
||||
}
|
||||
if (data.vscodeUrl) {
|
||||
const vsBtn = document.querySelector('#vsTerminal a');
|
||||
if (vsBtn) vsBtn.setAttribute('onclick', `window.location.href = '${data.vscodeUrl}'`);
|
||||
}
|
||||
if (data.cursorUrl) {
|
||||
const cursorBtn = document.querySelector('#cursorTerminal a');
|
||||
if (cursorBtn) cursorBtn.setAttribute('onclick', `window.location.href = '${data.cursorUrl}'`);
|
||||
}
|
||||
if (data.windsurfUrl) {
|
||||
const windsurfBtn = document.querySelector('#windsurfTerminal a');
|
||||
if (windsurfBtn) windsurfBtn.setAttribute('onclick', `window.location.href = '${data.windsurfUrl}'`);
|
||||
}
|
||||
if (data.traeUrl) {
|
||||
const traeBtn = document.querySelector('#traeTerminal a');
|
||||
if (traeBtn) traeBtn.setAttribute('onclick', `window.location.href = '${data.traeUrl}'`);
|
||||
// Update IDE URLs dynamically
|
||||
if (data.ideURLs) {
|
||||
for (const [ideName, url] of Object.entries(data.ideURLs)) {
|
||||
const terminal = document.getElementById(`${ideName}Terminal`);
|
||||
if (terminal) {
|
||||
const link = terminal.querySelector('a');
|
||||
if (link) {
|
||||
link.setAttribute('onclick', `window.location.href = '${url}'`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
displayElement();
|
||||
if (loadingElement) loadingElement.style.display = 'none';
|
||||
|
||||
@@ -11,6 +11,14 @@ import {initFomanticTab} from './fomantic/tab.ts';
|
||||
export const fomanticMobileScreen = window.matchMedia('only screen and (max-width: 767.98px)');
|
||||
|
||||
export function initGiteaFomantic() {
|
||||
// Guard against race conditions where fomantic.js hasn't been fully initialized yet.
|
||||
// This can happen on pages like Settings when document.readyState is already 'interactive'
|
||||
// or 'complete' when index.js executes, causing onDomReady to fire immediately.
|
||||
if (!$.fn.dropdown || !$.fn.dropdown.settings) {
|
||||
console.warn('Fomantic UI dropdown not initialized yet, skipping initGiteaFomantic');
|
||||
return;
|
||||
}
|
||||
|
||||
// our extensions
|
||||
$.fn.fomanticExt = {};
|
||||
// By default, use "exact match" for full text search
|
||||
|
||||
Reference in New Issue
Block a user