mirror of
https://github.com/siyuan-note/siyuan.git
synced 2025-12-16 22:50:13 +01:00
🎨 Improve the fallback logic for fetching README in the marketplace (#16551)
* 加载已下载插件列表时,如果插件指定 README 文件不存在,则回退到 README.md https://github.com/siyuan-note/siyuan/issues/14636#issuecomment-3035905944 * 加载已下载插件列表时,如果插件指定 README 文件不存在,则回退到 README.md https://github.com/siyuan-note/siyuan/issues/14636#issuecomment-3035905944 * 提取公共函数 * 获取首选 Readme Name Desc 时优先回退到指定的默认值 * 兼容赞助链接 * 在线获取 README 时最后回退到 README.md
This commit is contained in:
parent
d11ed21f06
commit
058ade01c7
6 changed files with 108 additions and 78 deletions
|
|
@ -169,9 +169,9 @@ func InstalledIcons() (ret []*Icon) {
|
||||||
icon.PreferredFunding = getPreferredFunding(icon.Funding)
|
icon.PreferredFunding = getPreferredFunding(icon.Funding)
|
||||||
icon.PreferredName = GetPreferredName(icon.Package)
|
icon.PreferredName = GetPreferredName(icon.Package)
|
||||||
icon.PreferredDesc = getPreferredDesc(icon.Description)
|
icon.PreferredDesc = getPreferredDesc(icon.Description)
|
||||||
info, statErr := os.Stat(filepath.Join(installPath, "README.md"))
|
info, statErr := os.Stat(filepath.Join(installPath, "icon.json"))
|
||||||
if nil != statErr {
|
if nil != statErr {
|
||||||
logging.LogWarnf("stat install theme README.md failed: %s", statErr)
|
logging.LogWarnf("stat install icon.json failed: %s", statErr)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
icon.HInstallDate = info.ModTime().Format("2006-01-02")
|
icon.HInstallDate = info.ModTime().Format("2006-01-02")
|
||||||
|
|
@ -183,14 +183,7 @@ func InstalledIcons() (ret []*Icon) {
|
||||||
packageInstallSizeCache.SetDefault(icon.RepoURL, is)
|
packageInstallSizeCache.SetDefault(icon.RepoURL, is)
|
||||||
}
|
}
|
||||||
icon.HInstallSize = humanize.BytesCustomCeil(uint64(icon.InstallSize), 2)
|
icon.HInstallSize = humanize.BytesCustomCeil(uint64(icon.InstallSize), 2)
|
||||||
readmeFilename := getPreferredReadme(icon.Readme)
|
icon.PreferredReadme = loadInstalledReadme(installPath, "/appearance/icons/"+dirName+"/", icon.Readme)
|
||||||
readme, readErr := os.ReadFile(filepath.Join(installPath, readmeFilename))
|
|
||||||
if nil != readErr {
|
|
||||||
logging.LogWarnf("read installed README.md failed: %s", readErr)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
icon.PreferredReadme, _ = renderLocalREADME("/appearance/icons/"+dirName+"/", readme)
|
|
||||||
icon.Outdated = isOutdatedIcon(icon, bazaarIcons)
|
icon.Outdated = isOutdatedIcon(icon, bazaarIcons)
|
||||||
ret = append(ret, icon)
|
ret = append(ret, icon)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -174,7 +174,7 @@ func getPreferredReadme(readme *Readme) string {
|
||||||
return "README.md"
|
return "README.md"
|
||||||
}
|
}
|
||||||
|
|
||||||
ret := readme.Default
|
var ret string
|
||||||
switch util.Lang {
|
switch util.Lang {
|
||||||
case "ar_SA":
|
case "ar_SA":
|
||||||
if "" != readme.ArSA {
|
if "" != readme.ArSA {
|
||||||
|
|
@ -232,13 +232,14 @@ func getPreferredReadme(readme *Readme) string {
|
||||||
if "" != readme.ZhCN {
|
if "" != readme.ZhCN {
|
||||||
ret = readme.ZhCN
|
ret = readme.ZhCN
|
||||||
}
|
}
|
||||||
default:
|
|
||||||
if "" != readme.EnUS {
|
|
||||||
ret = readme.EnUS
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if "" == ret {
|
if "" == strings.TrimSpace(ret) {
|
||||||
ret = "README.md"
|
defaultReadme := strings.TrimSpace(readme.Default)
|
||||||
|
if defaultReadme != "" {
|
||||||
|
ret = defaultReadme
|
||||||
|
} else {
|
||||||
|
ret = "README.md"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
@ -248,7 +249,7 @@ func GetPreferredName(pkg *Package) string {
|
||||||
return pkg.Name
|
return pkg.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
ret := pkg.DisplayName.Default
|
var ret string
|
||||||
switch util.Lang {
|
switch util.Lang {
|
||||||
case "ar_SA":
|
case "ar_SA":
|
||||||
if "" != pkg.DisplayName.ArSA {
|
if "" != pkg.DisplayName.ArSA {
|
||||||
|
|
@ -306,13 +307,14 @@ func GetPreferredName(pkg *Package) string {
|
||||||
if "" != pkg.DisplayName.ZhCN {
|
if "" != pkg.DisplayName.ZhCN {
|
||||||
ret = pkg.DisplayName.ZhCN
|
ret = pkg.DisplayName.ZhCN
|
||||||
}
|
}
|
||||||
default:
|
|
||||||
if "" != pkg.DisplayName.EnUS {
|
|
||||||
ret = pkg.DisplayName.EnUS
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if "" == ret {
|
if "" == strings.TrimSpace(ret) {
|
||||||
ret = pkg.Name
|
defaultName := strings.TrimSpace(pkg.DisplayName.Default)
|
||||||
|
if defaultName != "" {
|
||||||
|
ret = defaultName
|
||||||
|
} else {
|
||||||
|
ret = pkg.Name
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
@ -322,7 +324,7 @@ func getPreferredDesc(desc *Description) string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
ret := desc.Default
|
var ret string
|
||||||
switch util.Lang {
|
switch util.Lang {
|
||||||
case "ar_SA":
|
case "ar_SA":
|
||||||
if "" != desc.ArSA {
|
if "" != desc.ArSA {
|
||||||
|
|
@ -380,13 +382,12 @@ func getPreferredDesc(desc *Description) string {
|
||||||
if "" != desc.ZhCN {
|
if "" != desc.ZhCN {
|
||||||
ret = desc.ZhCN
|
ret = desc.ZhCN
|
||||||
}
|
}
|
||||||
default:
|
|
||||||
if "" != desc.EnUS {
|
|
||||||
ret = desc.EnUS
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if "" == ret {
|
if "" == strings.TrimSpace(ret) {
|
||||||
ret = desc.EnUS
|
defaultDesc := strings.TrimSpace(desc.Default)
|
||||||
|
if defaultDesc != "" {
|
||||||
|
ret = defaultDesc
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
@ -397,12 +398,21 @@ func getPreferredFunding(funding *Funding) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
if "" != funding.OpenCollective {
|
if "" != funding.OpenCollective {
|
||||||
|
if strings.HasPrefix(funding.OpenCollective, "http://") || strings.HasPrefix(funding.OpenCollective, "https://") {
|
||||||
|
return funding.OpenCollective
|
||||||
|
}
|
||||||
return "https://opencollective.com/" + funding.OpenCollective
|
return "https://opencollective.com/" + funding.OpenCollective
|
||||||
}
|
}
|
||||||
if "" != funding.Patreon {
|
if "" != funding.Patreon {
|
||||||
|
if strings.HasPrefix(funding.Patreon, "http://") || strings.HasPrefix(funding.Patreon, "https://") {
|
||||||
|
return funding.Patreon
|
||||||
|
}
|
||||||
return "https://www.patreon.com/" + funding.Patreon
|
return "https://www.patreon.com/" + funding.Patreon
|
||||||
}
|
}
|
||||||
if "" != funding.GitHub {
|
if "" != funding.GitHub {
|
||||||
|
if strings.HasPrefix(funding.GitHub, "http://") || strings.HasPrefix(funding.GitHub, "https://") {
|
||||||
|
return funding.GitHub
|
||||||
|
}
|
||||||
return "https://github.com/sponsors/" + funding.GitHub
|
return "https://github.com/sponsors/" + funding.GitHub
|
||||||
}
|
}
|
||||||
if 0 < len(funding.Custom) {
|
if 0 < len(funding.Custom) {
|
||||||
|
|
@ -684,14 +694,29 @@ func GetPackageREADME(repoURL, repoHash, packageType string) (ret string) {
|
||||||
|
|
||||||
data, err := downloadPackage(repoURLHash+"/"+readme, false, "")
|
data, err := downloadPackage(repoURLHash+"/"+readme, false, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ret = fmt.Sprintf("Load bazaar package's README.md(%s) failed: %s", readme, err.Error())
|
ret = fmt.Sprintf("Load bazaar package's preferred README(%s) failed: %s", readme, err.Error())
|
||||||
if readme == repo.Package.Readme.Default || "" == strings.TrimSpace(repo.Package.Readme.Default) {
|
// 回退到 Default README
|
||||||
return
|
var defaultReadme string
|
||||||
|
if nil != repo.Package.Readme {
|
||||||
|
defaultReadme = repo.Package.Readme.Default
|
||||||
}
|
}
|
||||||
readme = repo.Package.Readme.Default
|
if "" == strings.TrimSpace(defaultReadme) {
|
||||||
data, err = downloadPackage(repoURLHash+"/"+readme, false, "")
|
defaultReadme = "README.md"
|
||||||
if err != nil {
|
}
|
||||||
ret += fmt.Sprintf("<br>Load bazaar package's README.md(%s) failed: %s", readme, err.Error())
|
if readme != defaultReadme {
|
||||||
|
data, err = downloadPackage(repoURLHash+"/"+defaultReadme, false, "")
|
||||||
|
if err != nil {
|
||||||
|
ret += fmt.Sprintf("<br>Load bazaar package's default README(%s) failed: %s", defaultReadme, err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 回退到 README.md
|
||||||
|
if err != nil && readme != "README.md" && defaultReadme != "README.md" {
|
||||||
|
data, err = downloadPackage(repoURLHash+"/README.md", false, "")
|
||||||
|
if err != nil {
|
||||||
|
ret += fmt.Sprintf("<br>Load bazaar package's README.md failed: %s", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -708,6 +733,46 @@ func GetPackageREADME(repoURL, repoHash, packageType string) (ret string) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func loadInstalledReadme(installPath, basePath string, readme *Readme) (ret string) {
|
||||||
|
readmeFilename := getPreferredReadme(readme)
|
||||||
|
readmeData, readErr := os.ReadFile(filepath.Join(installPath, readmeFilename))
|
||||||
|
if nil == readErr {
|
||||||
|
ret, _ = renderLocalREADME(basePath, readmeData)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
logging.LogWarnf("read installed %s failed: %s", readmeFilename, readErr)
|
||||||
|
ret = fmt.Sprintf("File %s not found", readmeFilename)
|
||||||
|
// 回退到 Default README
|
||||||
|
var defaultReadme string
|
||||||
|
if nil != readme {
|
||||||
|
defaultReadme = strings.TrimSpace(readme.Default)
|
||||||
|
}
|
||||||
|
if "" == defaultReadme {
|
||||||
|
defaultReadme = "README.md"
|
||||||
|
}
|
||||||
|
if readmeFilename != defaultReadme {
|
||||||
|
readmeData, readErr = os.ReadFile(filepath.Join(installPath, defaultReadme))
|
||||||
|
if nil == readErr {
|
||||||
|
ret, _ = renderLocalREADME(basePath, readmeData)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
logging.LogWarnf("read installed %s failed: %s", defaultReadme, readErr)
|
||||||
|
ret += fmt.Sprintf("<br>File %s not found", defaultReadme)
|
||||||
|
}
|
||||||
|
// 回退到 README.md
|
||||||
|
if nil != readErr && readmeFilename != "README.md" && defaultReadme != "README.md" {
|
||||||
|
readmeData, readErr = os.ReadFile(filepath.Join(installPath, "README.md"))
|
||||||
|
if nil == readErr {
|
||||||
|
ret, _ = renderLocalREADME(basePath, readmeData)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
logging.LogWarnf("read installed README.md failed: %s", readErr)
|
||||||
|
ret += "<br>File README.md not found"
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func renderREADME(repoURL string, mdData []byte) (ret string, err error) {
|
func renderREADME(repoURL string, mdData []byte) (ret string, err error) {
|
||||||
luteEngine := lute.New()
|
luteEngine := lute.New()
|
||||||
luteEngine.SetSoftBreak2HardBreak(false)
|
luteEngine.SetSoftBreak2HardBreak(false)
|
||||||
|
|
|
||||||
|
|
@ -207,9 +207,9 @@ func InstalledPlugins(frontend string, checkUpdate bool) (ret []*Plugin) {
|
||||||
plugin.PreferredFunding = getPreferredFunding(plugin.Funding)
|
plugin.PreferredFunding = getPreferredFunding(plugin.Funding)
|
||||||
plugin.PreferredName = GetPreferredName(plugin.Package)
|
plugin.PreferredName = GetPreferredName(plugin.Package)
|
||||||
plugin.PreferredDesc = getPreferredDesc(plugin.Description)
|
plugin.PreferredDesc = getPreferredDesc(plugin.Description)
|
||||||
info, statErr := os.Stat(filepath.Join(installPath, "README.md"))
|
info, statErr := os.Stat(filepath.Join(installPath, "plugin.json"))
|
||||||
if nil != statErr {
|
if nil != statErr {
|
||||||
logging.LogWarnf("stat install theme README.md failed: %s", statErr)
|
logging.LogWarnf("stat install plugin.json failed: %s", statErr)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
plugin.HInstallDate = info.ModTime().Format("2006-01-02")
|
plugin.HInstallDate = info.ModTime().Format("2006-01-02")
|
||||||
|
|
@ -221,14 +221,7 @@ func InstalledPlugins(frontend string, checkUpdate bool) (ret []*Plugin) {
|
||||||
packageInstallSizeCache.SetDefault(plugin.RepoURL, is)
|
packageInstallSizeCache.SetDefault(plugin.RepoURL, is)
|
||||||
}
|
}
|
||||||
plugin.HInstallSize = humanize.BytesCustomCeil(uint64(plugin.InstallSize), 2)
|
plugin.HInstallSize = humanize.BytesCustomCeil(uint64(plugin.InstallSize), 2)
|
||||||
readmeFilename := getPreferredReadme(plugin.Readme)
|
plugin.PreferredReadme = loadInstalledReadme(installPath, "/plugins/"+dirName+"/", plugin.Readme)
|
||||||
readme, readErr := os.ReadFile(filepath.Join(installPath, readmeFilename))
|
|
||||||
if nil != readErr {
|
|
||||||
logging.LogWarnf("read installed README.md failed: %s", readErr)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
plugin.PreferredReadme, _ = renderLocalREADME("/plugins/"+dirName+"/", readme)
|
|
||||||
plugin.Outdated = isOutdatedPlugin(plugin, bazaarPlugins)
|
plugin.Outdated = isOutdatedPlugin(plugin, bazaarPlugins)
|
||||||
plugin.Incompatible = isIncompatiblePlugin(plugin, frontend)
|
plugin.Incompatible = isIncompatiblePlugin(plugin, frontend)
|
||||||
ret = append(ret, plugin)
|
ret = append(ret, plugin)
|
||||||
|
|
|
||||||
|
|
@ -170,9 +170,9 @@ func InstalledTemplates() (ret []*Template) {
|
||||||
template.PreferredFunding = getPreferredFunding(template.Funding)
|
template.PreferredFunding = getPreferredFunding(template.Funding)
|
||||||
template.PreferredName = GetPreferredName(template.Package)
|
template.PreferredName = GetPreferredName(template.Package)
|
||||||
template.PreferredDesc = getPreferredDesc(template.Description)
|
template.PreferredDesc = getPreferredDesc(template.Description)
|
||||||
info, statErr := os.Stat(filepath.Join(installPath, "README.md"))
|
info, statErr := os.Stat(filepath.Join(installPath, "template.json"))
|
||||||
if nil != statErr {
|
if nil != statErr {
|
||||||
logging.LogWarnf("stat install theme README.md failed: %s", statErr)
|
logging.LogWarnf("stat install template.json failed: %s", statErr)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
template.HInstallDate = info.ModTime().Format("2006-01-02")
|
template.HInstallDate = info.ModTime().Format("2006-01-02")
|
||||||
|
|
@ -184,14 +184,7 @@ func InstalledTemplates() (ret []*Template) {
|
||||||
packageInstallSizeCache.SetDefault(template.RepoURL, is)
|
packageInstallSizeCache.SetDefault(template.RepoURL, is)
|
||||||
}
|
}
|
||||||
template.HInstallSize = humanize.BytesCustomCeil(uint64(template.InstallSize), 2)
|
template.HInstallSize = humanize.BytesCustomCeil(uint64(template.InstallSize), 2)
|
||||||
readmeFilename := getPreferredReadme(template.Readme)
|
template.PreferredReadme = loadInstalledReadme(installPath, "/templates/"+dirName+"/", template.Readme)
|
||||||
readme, readErr := os.ReadFile(filepath.Join(installPath, readmeFilename))
|
|
||||||
if nil != readErr {
|
|
||||||
logging.LogWarnf("read installed README.md failed: %s", readErr)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
template.PreferredReadme, _ = renderLocalREADME("/templates/"+dirName+"/", readme)
|
|
||||||
template.Outdated = isOutdatedTemplate(template, bazaarTemplates)
|
template.Outdated = isOutdatedTemplate(template, bazaarTemplates)
|
||||||
ret = append(ret, template)
|
ret = append(ret, template)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -171,9 +171,9 @@ func InstalledThemes() (ret []*Theme) {
|
||||||
theme.PreferredFunding = getPreferredFunding(theme.Funding)
|
theme.PreferredFunding = getPreferredFunding(theme.Funding)
|
||||||
theme.PreferredName = GetPreferredName(theme.Package)
|
theme.PreferredName = GetPreferredName(theme.Package)
|
||||||
theme.PreferredDesc = getPreferredDesc(theme.Description)
|
theme.PreferredDesc = getPreferredDesc(theme.Description)
|
||||||
info, statErr := os.Stat(filepath.Join(installPath, "README.md"))
|
info, statErr := os.Stat(filepath.Join(installPath, "theme.json"))
|
||||||
if nil != statErr {
|
if nil != statErr {
|
||||||
logging.LogWarnf("stat install theme README.md failed: %s", statErr)
|
logging.LogWarnf("stat install theme.json failed: %s", statErr)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
theme.HInstallDate = info.ModTime().Format("2006-01-02")
|
theme.HInstallDate = info.ModTime().Format("2006-01-02")
|
||||||
|
|
@ -185,14 +185,7 @@ func InstalledThemes() (ret []*Theme) {
|
||||||
packageInstallSizeCache.SetDefault(theme.RepoURL, is)
|
packageInstallSizeCache.SetDefault(theme.RepoURL, is)
|
||||||
}
|
}
|
||||||
theme.HInstallSize = humanize.BytesCustomCeil(uint64(theme.InstallSize), 2)
|
theme.HInstallSize = humanize.BytesCustomCeil(uint64(theme.InstallSize), 2)
|
||||||
readmeFilename := getPreferredReadme(theme.Readme)
|
theme.PreferredReadme = loadInstalledReadme(installPath, "/appearance/themes/"+dirName+"/", theme.Readme)
|
||||||
readme, readErr := os.ReadFile(filepath.Join(installPath, readmeFilename))
|
|
||||||
if nil != readErr {
|
|
||||||
logging.LogWarnf("read installed README.md failed: %s", readErr)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
theme.PreferredReadme, _ = renderLocalREADME("/appearance/themes/"+dirName+"/", readme)
|
|
||||||
theme.Outdated = isOutdatedTheme(theme, bazaarThemes)
|
theme.Outdated = isOutdatedTheme(theme, bazaarThemes)
|
||||||
ret = append(ret, theme)
|
ret = append(ret, theme)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -167,9 +167,9 @@ func InstalledWidgets() (ret []*Widget) {
|
||||||
widget.PreferredFunding = getPreferredFunding(widget.Funding)
|
widget.PreferredFunding = getPreferredFunding(widget.Funding)
|
||||||
widget.PreferredName = GetPreferredName(widget.Package)
|
widget.PreferredName = GetPreferredName(widget.Package)
|
||||||
widget.PreferredDesc = getPreferredDesc(widget.Description)
|
widget.PreferredDesc = getPreferredDesc(widget.Description)
|
||||||
info, statErr := os.Stat(filepath.Join(installPath, "README.md"))
|
info, statErr := os.Stat(filepath.Join(installPath, "widget.json"))
|
||||||
if nil != statErr {
|
if nil != statErr {
|
||||||
logging.LogWarnf("stat install theme README.md failed: %s", statErr)
|
logging.LogWarnf("stat install widget.json failed: %s", statErr)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
widget.HInstallDate = info.ModTime().Format("2006-01-02")
|
widget.HInstallDate = info.ModTime().Format("2006-01-02")
|
||||||
|
|
@ -181,14 +181,7 @@ func InstalledWidgets() (ret []*Widget) {
|
||||||
packageInstallSizeCache.SetDefault(widget.RepoURL, is)
|
packageInstallSizeCache.SetDefault(widget.RepoURL, is)
|
||||||
}
|
}
|
||||||
widget.HInstallSize = humanize.BytesCustomCeil(uint64(widget.InstallSize), 2)
|
widget.HInstallSize = humanize.BytesCustomCeil(uint64(widget.InstallSize), 2)
|
||||||
readmeFilename := getPreferredReadme(widget.Readme)
|
widget.PreferredReadme = loadInstalledReadme(installPath, "/widgets/"+dirName+"/", widget.Readme)
|
||||||
readme, readErr := os.ReadFile(filepath.Join(installPath, readmeFilename))
|
|
||||||
if nil != readErr {
|
|
||||||
logging.LogWarnf("read installed README.md failed: %s", readErr)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
widget.PreferredReadme, _ = renderLocalREADME("/widgets/"+dirName+"/", readme)
|
|
||||||
widget.Outdated = isOutdatedWidget(widget, bazaarWidgets)
|
widget.Outdated = isOutdatedWidget(widget, bazaarWidgets)
|
||||||
ret = append(ret, widget)
|
ret = append(ret, widget)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue