Introduced length limits
This commit is contained in:
parent
9338f7bdeb
commit
3ef41b1cdd
6
arn/limits/limits.go
Normal file
6
arn/limits/limits.go
Normal file
@ -0,0 +1,6 @@
|
||||
package limits
|
||||
|
||||
const (
|
||||
DefaultTextMaxLength = 100
|
||||
DefaultTextAreaMaxLength = 20000
|
||||
)
|
@ -25,7 +25,7 @@ func AMVs(originalTerm string, maxLength int) []*arn.AMV {
|
||||
text := strings.ToLower(amv.Title.Canonical)
|
||||
similarity := stringutils.AdvancedStringSimilarity(term, text)
|
||||
|
||||
if similarity >= MinimumStringSimilarity {
|
||||
if similarity >= MinStringSimilarity {
|
||||
results = append(results, &Result{
|
||||
obj: amv,
|
||||
similarity: similarity,
|
||||
@ -36,7 +36,7 @@ func AMVs(originalTerm string, maxLength int) []*arn.AMV {
|
||||
text = strings.ToLower(amv.Title.Native)
|
||||
similarity = stringutils.AdvancedStringSimilarity(term, text)
|
||||
|
||||
if similarity >= MinimumStringSimilarity {
|
||||
if similarity >= MinStringSimilarity {
|
||||
results = append(results, &Result{
|
||||
obj: amv,
|
||||
similarity: similarity,
|
||||
|
@ -1,16 +1,24 @@
|
||||
package search
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/aerogo/flow"
|
||||
"github.com/animenotifier/notify.moe/arn"
|
||||
)
|
||||
|
||||
// MinimumStringSimilarity is the minimum JaroWinkler distance we accept for search results.
|
||||
const MinimumStringSimilarity = 0.89
|
||||
// MinStringSimilarity is the minimum JaroWinkler distance we accept for search results.
|
||||
const MinStringSimilarity = 0.89
|
||||
|
||||
// MaxSearchTermLength defines how long the search term can be.
|
||||
const MaxSearchTermLength = 100
|
||||
|
||||
// popularityDamping reduces the factor of popularity in search results.
|
||||
const popularityDamping = 0.0009
|
||||
|
||||
// ErrTermTooLong is used when the search term is too long
|
||||
var ErrTermTooLong = fmt.Errorf("Search term is too long (maximum %d characters)", MaxSearchTermLength)
|
||||
|
||||
// Result ...
|
||||
type Result struct {
|
||||
obj interface{}
|
||||
@ -23,6 +31,10 @@ func All(term string, maxUsers, maxAnime, maxPosts, maxThreads, maxTracks, maxCh
|
||||
return nil, nil, nil, nil, nil, nil, nil, nil
|
||||
}
|
||||
|
||||
if len(term) > MaxSearchTermLength {
|
||||
return nil, nil, nil, nil, nil, nil, nil, nil
|
||||
}
|
||||
|
||||
var (
|
||||
userResults []*arn.User
|
||||
animeResults []*arn.Anime
|
||||
|
@ -42,7 +42,7 @@ func Anime(originalTerm string, maxLength int) []*arn.Anime {
|
||||
// Canonical title
|
||||
similarity := check(anime.Title.Canonical)
|
||||
|
||||
if similarity >= MinimumStringSimilarity {
|
||||
if similarity >= MinStringSimilarity {
|
||||
add(anime, similarity)
|
||||
continue
|
||||
}
|
||||
@ -50,7 +50,7 @@ func Anime(originalTerm string, maxLength int) []*arn.Anime {
|
||||
// English
|
||||
similarity = check(anime.Title.English)
|
||||
|
||||
if similarity >= MinimumStringSimilarity {
|
||||
if similarity >= MinStringSimilarity {
|
||||
add(anime, similarity)
|
||||
continue
|
||||
}
|
||||
@ -58,7 +58,7 @@ func Anime(originalTerm string, maxLength int) []*arn.Anime {
|
||||
// Romaji
|
||||
similarity = check(anime.Title.Romaji)
|
||||
|
||||
if similarity >= MinimumStringSimilarity {
|
||||
if similarity >= MinStringSimilarity {
|
||||
add(anime, similarity)
|
||||
continue
|
||||
}
|
||||
@ -67,7 +67,7 @@ func Anime(originalTerm string, maxLength int) []*arn.Anime {
|
||||
for _, synonym := range anime.Title.Synonyms {
|
||||
similarity := check(synonym)
|
||||
|
||||
if similarity >= MinimumStringSimilarity {
|
||||
if similarity >= MinStringSimilarity {
|
||||
add(anime, similarity)
|
||||
goto nextAnime
|
||||
}
|
||||
@ -76,7 +76,7 @@ func Anime(originalTerm string, maxLength int) []*arn.Anime {
|
||||
// Japanese
|
||||
similarity = check(anime.Title.Japanese)
|
||||
|
||||
if similarity >= MinimumStringSimilarity {
|
||||
if similarity >= MinStringSimilarity {
|
||||
add(anime, similarity)
|
||||
continue
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ func Companies(originalTerm string, maxLength int) []*arn.Company {
|
||||
text := strings.ToLower(stringutils.RemoveSpecialCharacters(company.Name.English))
|
||||
similarity := stringutils.AdvancedStringSimilarity(term, text)
|
||||
|
||||
if similarity >= MinimumStringSimilarity {
|
||||
if similarity >= MinStringSimilarity {
|
||||
results = append(results, &Result{
|
||||
obj: company,
|
||||
similarity: similarity,
|
||||
|
@ -25,7 +25,7 @@ func SoundTracks(originalTerm string, maxLength int) []*arn.SoundTrack {
|
||||
text := strings.ToLower(track.Title.Canonical)
|
||||
similarity := stringutils.AdvancedStringSimilarity(term, text)
|
||||
|
||||
if similarity >= MinimumStringSimilarity {
|
||||
if similarity >= MinStringSimilarity {
|
||||
results = append(results, &Result{
|
||||
obj: track,
|
||||
similarity: similarity,
|
||||
@ -36,7 +36,7 @@ func SoundTracks(originalTerm string, maxLength int) []*arn.SoundTrack {
|
||||
text = strings.ToLower(track.Title.Native)
|
||||
similarity = stringutils.AdvancedStringSimilarity(term, text)
|
||||
|
||||
if similarity >= MinimumStringSimilarity {
|
||||
if similarity >= MinStringSimilarity {
|
||||
results = append(results, &Result{
|
||||
obj: track,
|
||||
similarity: similarity,
|
||||
|
@ -23,7 +23,7 @@ func Users(originalTerm string, maxLength int) []*arn.User {
|
||||
// Similarity check
|
||||
similarity := stringutils.AdvancedStringSimilarity(term, text)
|
||||
|
||||
if similarity < MinimumStringSimilarity {
|
||||
if similarity < MinStringSimilarity {
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -1,2 +1,2 @@
|
||||
component FuzzySearch(value string)
|
||||
input#search.action(data-action="search", data-trigger="input", type="search", autocomplete="off", autocorrect="off", autocapitalize="none", spellcheck="false", placeholder="Search...", title="Shortcut: F", value=value)
|
||||
input#search.action(data-action="search", data-trigger="input", type="search", autocomplete="off", autocorrect="off", autocapitalize="none", spellcheck="false", placeholder="Search...", title="Shortcut: F", maxlength="100", value=value)
|
@ -1,7 +1,7 @@
|
||||
component InputText(id string, value string, label string, placeholder string)
|
||||
component InputText(id string, value string, label string, placeholder string, maxLength int)
|
||||
.widget-section
|
||||
label(for=id)= label + ":"
|
||||
input.widget-ui-element.action(id=id, data-field=id, type="text", value=value, placeholder=placeholder, title=placeholder, data-action="save", data-trigger="change")
|
||||
input.widget-ui-element.action(id=id, data-field=id, type="text", value=value, placeholder=placeholder, title=placeholder, data-action="save", data-trigger="change", maxlength=maxLength)
|
||||
|
||||
component InputBool(id string, value bool, label string, title string)
|
||||
.widget-section
|
||||
@ -16,10 +16,10 @@ component InputBool(id string, value bool, label string, title string)
|
||||
span OFF
|
||||
//- input.widget-ui-element.action(id=id, data-field=id, type="checkbox", value=value, checked=value, data-action="save", data-trigger="change")
|
||||
|
||||
component InputTextArea(id string, value string, label string, placeholder string)
|
||||
component InputTextArea(id string, value string, label string, placeholder string, maxLength int)
|
||||
.widget-section
|
||||
label(for=id)= label + ":"
|
||||
textarea.widget-ui-element.action(id=id, data-field=id, placeholder=placeholder, title=placeholder, data-action="save", data-trigger="change")= value
|
||||
textarea.widget-ui-element.action(id=id, data-field=id, placeholder=placeholder, title=placeholder, data-action="save", data-trigger="change", maxlength=maxLength)= value
|
||||
|
||||
component InputNumber(id string, value float64, label string, placeholder string, min string, max string, step string)
|
||||
.widget-section
|
||||
|
@ -4,7 +4,7 @@ component NewPostArea(parent arn.PostParent, user *arn.User, placeholder string)
|
||||
.post-author
|
||||
Avatar(user)
|
||||
|
||||
textarea#new-post-text.post-content(placeholder=placeholder + "...", aria-label=placeholder)
|
||||
textarea#new-post-text.post-content(placeholder=placeholder + "...", aria-label=placeholder, maxlength=limits.DefaultTextAreaMaxLength)
|
||||
|
||||
if !arn.IsLocked(parent)
|
||||
NewPostActions(parent, false)
|
||||
|
@ -40,7 +40,7 @@ component Postable(post arn.Postable, user *arn.User, includeReplies bool, showP
|
||||
if post.TypeName() == "Thread"
|
||||
input.post-title-input.hidden(id="title-" + post.GetID(), value=post.TitleByUser(user), type="text", placeholder="Thread title")
|
||||
|
||||
textarea.post-text-input.hidden(id="source-" + post.GetID())= post.GetText()
|
||||
textarea.post-text-input.hidden(id="source-" + post.GetID(), maxlength=limits.DefaultTextAreaMaxLength)= post.GetText()
|
||||
|
||||
.buttons.hidden(id="edit-toolbar-" + post.GetID())
|
||||
a.button.post-save.action(data-action="savePost", data-trigger="click", data-id=post.GetID())
|
||||
|
@ -26,7 +26,7 @@ component AnimeListItem(viewUser *arn.User, item *arn.AnimeListItem, anime *arn.
|
||||
InputBool("Private", item.Private, "Private", "Hidden entry")
|
||||
|
||||
.mountable
|
||||
InputTextArea("Notes", item.Notes, "Notes", "Your notes")
|
||||
InputTextArea("Notes", item.Notes, "Notes", "Your notes", 2000)
|
||||
|
||||
.buttons.mountable
|
||||
a.button.mountable(href="/+" + viewUser.Nick + "/animelist/" + item.Status)
|
||||
|
@ -5,7 +5,7 @@ component NewThread(user *arn.User)
|
||||
.widget
|
||||
input#title.widget-ui-element(type="text", placeholder="Title")
|
||||
|
||||
textarea#text.widget-ui-element(placeholder="Content")
|
||||
textarea#text.widget-ui-element(placeholder="Content", maxlength=limits.DefaultTextAreaMaxLength)
|
||||
|
||||
select#tag.widget-ui-element(value="general")
|
||||
option(value="general") General
|
||||
|
@ -1,3 +1,3 @@
|
||||
component MultiSearch
|
||||
textarea.action(data-action="multiSearchAnime", data-trigger="change", placeholder="Paste multiple anime titles here, one per line")
|
||||
textarea.action(data-action="multiSearchAnime", data-trigger="change", placeholder="Paste multiple anime titles here, one per line", maxlength=limits.DefaultTextAreaMaxLength)
|
||||
#multi-search-anime
|
@ -1,7 +1,7 @@
|
||||
package search
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"net/http"
|
||||
|
||||
"github.com/animenotifier/notify.moe/utils"
|
||||
|
||||
@ -24,9 +24,12 @@ const (
|
||||
// Get search page.
|
||||
func Get(ctx aero.Context) error {
|
||||
term := ctx.Get("term")
|
||||
term = strings.TrimPrefix(term, "/")
|
||||
user := utils.GetUser(ctx)
|
||||
|
||||
if len(term) > search.MaxSearchTermLength {
|
||||
ctx.SetStatus(http.StatusRequestEntityTooLarge)
|
||||
}
|
||||
|
||||
users, animes, posts, threads, tracks, characters, amvs, companies := search.All(
|
||||
term,
|
||||
maxUsers,
|
||||
@ -50,9 +53,12 @@ func GetEmptySearch(ctx aero.Context) error {
|
||||
// Anime search.
|
||||
func Anime(ctx aero.Context) error {
|
||||
term := ctx.Get("term")
|
||||
term = strings.TrimPrefix(term, "/")
|
||||
user := utils.GetUser(ctx)
|
||||
|
||||
if len(term) > search.MaxSearchTermLength {
|
||||
ctx.SetStatus(http.StatusRequestEntityTooLarge)
|
||||
}
|
||||
|
||||
animes := search.Anime(term, maxAnime)
|
||||
return ctx.HTML(components.AnimeSearchResults(animes, user))
|
||||
}
|
||||
@ -60,9 +66,12 @@ func Anime(ctx aero.Context) error {
|
||||
// Characters search.
|
||||
func Characters(ctx aero.Context) error {
|
||||
term := ctx.Get("term")
|
||||
term = strings.TrimPrefix(term, "/")
|
||||
user := utils.GetUser(ctx)
|
||||
|
||||
if len(term) > search.MaxSearchTermLength {
|
||||
ctx.SetStatus(http.StatusRequestEntityTooLarge)
|
||||
}
|
||||
|
||||
characters := search.Characters(term, maxCharacters)
|
||||
return ctx.HTML(components.CharacterSearchResults(characters, user))
|
||||
}
|
||||
@ -70,29 +79,38 @@ func Characters(ctx aero.Context) error {
|
||||
// Posts search.
|
||||
func Posts(ctx aero.Context) error {
|
||||
term := ctx.Get("term")
|
||||
term = strings.TrimPrefix(term, "/")
|
||||
user := utils.GetUser(ctx)
|
||||
posts := search.Posts(term, maxPosts)
|
||||
|
||||
if len(term) > search.MaxSearchTermLength {
|
||||
ctx.SetStatus(http.StatusRequestEntityTooLarge)
|
||||
}
|
||||
|
||||
posts := search.Posts(term, maxPosts)
|
||||
return ctx.HTML(components.PostsSearchResults(posts, user))
|
||||
}
|
||||
|
||||
// Threads search.
|
||||
func Threads(ctx aero.Context) error {
|
||||
term := ctx.Get("term")
|
||||
term = strings.TrimPrefix(term, "/")
|
||||
user := utils.GetUser(ctx)
|
||||
threads := search.Threads(term, maxThreads)
|
||||
|
||||
if len(term) > search.MaxSearchTermLength {
|
||||
ctx.SetStatus(http.StatusRequestEntityTooLarge)
|
||||
}
|
||||
|
||||
threads := search.Threads(term, maxThreads)
|
||||
return ctx.HTML(components.ThreadsSearchResults(threads, user))
|
||||
}
|
||||
|
||||
// SoundTracks search.
|
||||
func SoundTracks(ctx aero.Context) error {
|
||||
term := ctx.Get("term")
|
||||
term = strings.TrimPrefix(term, "/")
|
||||
user := utils.GetUser(ctx)
|
||||
|
||||
if len(term) > search.MaxSearchTermLength {
|
||||
ctx.SetStatus(http.StatusRequestEntityTooLarge)
|
||||
}
|
||||
|
||||
tracks := search.SoundTracks(term, maxSoundTracks)
|
||||
return ctx.HTML(components.SoundTrackSearchResults(tracks, user))
|
||||
}
|
||||
@ -100,9 +118,12 @@ func SoundTracks(ctx aero.Context) error {
|
||||
// AMVs search.
|
||||
func AMVs(ctx aero.Context) error {
|
||||
term := ctx.Get("term")
|
||||
term = strings.TrimPrefix(term, "/")
|
||||
user := utils.GetUser(ctx)
|
||||
|
||||
if len(term) > search.MaxSearchTermLength {
|
||||
ctx.SetStatus(http.StatusRequestEntityTooLarge)
|
||||
}
|
||||
|
||||
amvs := search.AMVs(term, maxAMVs)
|
||||
return ctx.HTML(components.AMVSearchResults(amvs, user))
|
||||
}
|
||||
@ -110,7 +131,10 @@ func AMVs(ctx aero.Context) error {
|
||||
// Users search.
|
||||
func Users(ctx aero.Context) error {
|
||||
term := ctx.Get("term")
|
||||
term = strings.TrimPrefix(term, "/")
|
||||
|
||||
if len(term) > search.MaxSearchTermLength {
|
||||
ctx.SetStatus(http.StatusRequestEntityTooLarge)
|
||||
}
|
||||
|
||||
users := search.Users(term, maxUsers)
|
||||
return ctx.HTML(components.UserSearchResults(users))
|
||||
@ -119,7 +143,10 @@ func Users(ctx aero.Context) error {
|
||||
// Companies search.
|
||||
func Companies(ctx aero.Context) error {
|
||||
term := ctx.Get("term")
|
||||
term = strings.TrimPrefix(term, "/")
|
||||
|
||||
if len(term) > search.MaxSearchTermLength {
|
||||
ctx.SetStatus(http.StatusRequestEntityTooLarge)
|
||||
}
|
||||
|
||||
companies := search.Companies(term, maxCompanies)
|
||||
return ctx.HTML(components.CompanySearchResults(companies))
|
||||
|
@ -9,20 +9,20 @@ component SettingsAccounts(user *arn.User)
|
||||
Icon("cubes")
|
||||
span Accounts
|
||||
|
||||
InputText("Accounts.AniList.Nick", user.Accounts.AniList.Nick, "AniList", "Your username on anilist.co")
|
||||
InputText("Accounts.Kitsu.Nick", user.Accounts.Kitsu.Nick, "Kitsu", "Your username on kitsu.io")
|
||||
InputText("Accounts.MyAnimeList.Nick", user.Accounts.MyAnimeList.Nick, "MyAnimeList", "Your username on myanimelist.net")
|
||||
InputText("Accounts.Discord.Nick", user.Accounts.Discord.Nick, "Discord", "Your username on Discord")
|
||||
InputText("Accounts.AniList.Nick", user.Accounts.AniList.Nick, "AniList", "Your username on anilist.co", 30)
|
||||
InputText("Accounts.Kitsu.Nick", user.Accounts.Kitsu.Nick, "Kitsu", "Your username on kitsu.io", 30)
|
||||
InputText("Accounts.MyAnimeList.Nick", user.Accounts.MyAnimeList.Nick, "MyAnimeList", "Your username on myanimelist.net", 30)
|
||||
InputText("Accounts.Discord.Nick", user.Accounts.Discord.Nick, "Discord", "Your username on Discord", 30)
|
||||
|
||||
.widget.mountable(data-api="/api/user/" + user.ID)
|
||||
h3.widget-title
|
||||
Icon("gamepad")
|
||||
span Games
|
||||
|
||||
InputText("Accounts.FinalFantasyXIV.Nick", user.Accounts.FinalFantasyXIV.Nick, "Final Fantasy XIV", "Your character name on FFXIV")
|
||||
InputText("Accounts.FinalFantasyXIV.Nick", user.Accounts.FinalFantasyXIV.Nick, "Final Fantasy XIV", "Your character name on FFXIV", 30)
|
||||
InputSelection("Accounts.FinalFantasyXIV.Server", user.Accounts.FinalFantasyXIV.Server, "Final Fantasy XIV - World", "Your server/world on FFXIV", arn.DataLists["ffxiv-servers"])
|
||||
InputText("Accounts.Osu.Nick", user.Accounts.Osu.Nick, "Osu", "Your username on osu.ppy.sh")
|
||||
InputText("Accounts.Overwatch.BattleTag", user.Accounts.Overwatch.BattleTag, "Overwatch", "Your battletag on Overwatch")
|
||||
InputText("Accounts.Osu.Nick", user.Accounts.Osu.Nick, "Osu", "Your username on osu.ppy.sh", 30)
|
||||
InputText("Accounts.Overwatch.BattleTag", user.Accounts.Overwatch.BattleTag, "Overwatch", "Your battletag on Overwatch", 30)
|
||||
|
||||
.widget.mountable
|
||||
h3.widget-title
|
||||
|
@ -10,8 +10,8 @@ component SettingsInfo(user *arn.User)
|
||||
span Info
|
||||
|
||||
InputSelection("Gender", user.Gender, "Gender", "Your gender", arn.DataLists["genders"])
|
||||
InputText("BirthDay", user.BirthDay, "Birthday", "YYYY-MM-DD")
|
||||
InputText("Website", user.Website, "Website", "Your homepage")
|
||||
InputText("BirthDay", user.BirthDay, "Birthday", "YYYY-MM-DD", len("YYYY-MM-DD"))
|
||||
InputText("Website", user.Website, "Website", "Your homepage", 100)
|
||||
|
||||
.widget.mountable(data-api="/api/settings/" + user.ID)
|
||||
h3.widget-title
|
||||
|
@ -9,39 +9,14 @@ component SettingsPersonal(user *arn.User)
|
||||
Icon("user")
|
||||
span Personal
|
||||
|
||||
InputText("Nick", user.Nick, "Username", "Your username on notify.moe")
|
||||
InputTextArea("Introduction", user.Introduction, "Introduction", "Tell us a little bit about yourself")
|
||||
InputText("Nick", user.Nick, "Username", "Your username on notify.moe", 25)
|
||||
InputTextArea("Introduction", user.Introduction, "Introduction", "Tell us a little bit about yourself", 2000)
|
||||
|
||||
.widget.mountable(data-api="/api/settings/" + user.ID)
|
||||
h3.widget-title
|
||||
Icon("camera")
|
||||
span Avatar
|
||||
|
||||
//- .widget-section
|
||||
//- label(for="Avatar.Source") Source:
|
||||
//- select.widget-ui-element.action(id="Avatar.Source", data-field="Avatar.Source", value=user.Settings().Avatar.Source, data-action="save", data-trigger="change")
|
||||
//- option(value="") Automatic
|
||||
//- option(value="Gravatar") Gravatar
|
||||
//- option(value="URL") Link
|
||||
//- option(value="FileSystem") Upload
|
||||
|
||||
//- //- URL input
|
||||
//- if user.Settings().Avatar.Source == "URL"
|
||||
//- InputText("Avatar.SourceURL", user.Settings().Avatar.SourceURL, "Link", "Post the link to the image here")
|
||||
|
||||
//- //- Gravatar preview image
|
||||
//- if user.Settings().Avatar.Source == "Gravatar" || (user.Settings().Avatar.Source == "" && user.Avatar.Source == "Gravatar")
|
||||
//- .profile-image-container.avatar-preview
|
||||
//- img.profile-image.mountable(src=user.Gravatar(), alt="Gravatar (" + user.Email + ")", title="Gravatar (" + user.Email + ")")
|
||||
|
||||
//- //- URL preview image
|
||||
//- if user.Settings().Avatar.Source == "URL" && user.Settings().Avatar.SourceURL != ""
|
||||
//- .profile-image-container.avatar-preview
|
||||
//- img.profile-image.mountable(src=strings.Replace(user.Settings().Avatar.SourceURL, "http://", "https://", 1), alt="Avatar preview")
|
||||
|
||||
//- //- File upload
|
||||
//- if user.Settings().Avatar.Source == "FileSystem"
|
||||
|
||||
AvatarInput(user)
|
||||
|
||||
.widget.mountable(data-api="/api/settings/" + user.ID)
|
||||
|
@ -10,7 +10,7 @@ component Welcome(user *arn.User)
|
||||
|
||||
.mountable(data-api="/api/user/" + user.ID)
|
||||
//- [^\\W\\s\\d]{1,24}[A-Za-z]{1}
|
||||
InputText("Nick", user.CleanNick(), "Nick", "Your username on notify.moe")
|
||||
InputText("Nick", user.CleanNick(), "Nick", "Your username on notify.moe", 25)
|
||||
|
||||
.footer.mountable
|
||||
p Only letters and underscore.
|
||||
@ -26,7 +26,7 @@ component Welcome(user *arn.User)
|
||||
p.welcome-text.mountable Write a little introduction for your profile.
|
||||
|
||||
.mountable(data-api="/api/user/" + user.ID)
|
||||
InputTextArea("Introduction", user.Introduction, "Introduction", "Tell us a little bit about yourself")
|
||||
InputTextArea("Introduction", user.Introduction, "Introduction", "Tell us a little bit about yourself", 2000)
|
||||
|
||||
.footer.mountable
|
||||
p Markdown allowed.
|
||||
|
@ -34,9 +34,6 @@ const fetchOptions: RequestInit = {
|
||||
credentials: "same-origin"
|
||||
}
|
||||
|
||||
// Error message
|
||||
const searchErrorMessage = "Looks like the website is offline, please retry later."
|
||||
|
||||
// Speech recognition
|
||||
let recognition: SpeechRecognition
|
||||
|
||||
@ -122,7 +119,7 @@ export async function search(arn: AnimeNotifier, search: HTMLInputElement, evt?:
|
||||
// Start searching anime
|
||||
fetch("/_/anime-search/" + term, fetchOptions)
|
||||
.then(showResponseInElement(arn, url, "anime", results["anime"]))
|
||||
.catch(_ => arn.statusMessage.showError(searchErrorMessage))
|
||||
.catch(err => arn.statusMessage.showError(err))
|
||||
|
||||
requestIdleCallback(() => {
|
||||
// Check that the term hasn't changed in the meantime
|
||||
@ -138,7 +135,7 @@ export async function search(arn: AnimeNotifier, search: HTMLInputElement, evt?:
|
||||
|
||||
fetch(`/_/${key}-search/` + term, fetchOptions)
|
||||
.then(showResponseInElement(arn, url, key, results[key]))
|
||||
.catch(_ => arn.statusMessage.showError(searchErrorMessage))
|
||||
.catch(err => arn.statusMessage.showError(err))
|
||||
}
|
||||
})
|
||||
} catch(err) {
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
|
||||
"github.com/aerogo/api"
|
||||
"github.com/animenotifier/notify.moe/arn"
|
||||
"github.com/animenotifier/notify.moe/arn/limits"
|
||||
"github.com/animenotifier/notify.moe/components"
|
||||
"github.com/animenotifier/notify.moe/utils"
|
||||
)
|
||||
@ -214,7 +215,13 @@ func renderStringField(b io.StringWriter, v *reflect.Value, field reflect.Struct
|
||||
b.WriteString(components.InputSelection(idPrefix+field.Name, fieldValue.String(), field.Name, field.Tag.Get("tooltip"), values))
|
||||
|
||||
case field.Tag.Get("type") == "textarea":
|
||||
b.WriteString(components.InputTextArea(idPrefix+field.Name, fieldValue.String(), field.Name, field.Tag.Get("tooltip")))
|
||||
maxLength, err := strconv.Atoi(field.Tag.Get("maxLength"))
|
||||
|
||||
if err != nil {
|
||||
maxLength = limits.DefaultTextAreaMaxLength
|
||||
}
|
||||
|
||||
b.WriteString(components.InputTextArea(idPrefix+field.Name, fieldValue.String(), field.Name, field.Tag.Get("tooltip"), maxLength))
|
||||
|
||||
case field.Tag.Get("type") == "upload":
|
||||
endpoint := field.Tag.Get("endpoint")
|
||||
@ -224,7 +231,13 @@ func renderStringField(b io.StringWriter, v *reflect.Value, field reflect.Struct
|
||||
b.WriteString(components.InputFileUpload(idPrefix+field.Name, field.Name, field.Tag.Get("filetype"), endpoint))
|
||||
|
||||
default:
|
||||
b.WriteString(components.InputText(idPrefix+field.Name, fieldValue.String(), field.Name, field.Tag.Get("tooltip")))
|
||||
maxLength, err := strconv.Atoi(field.Tag.Get("maxLength"))
|
||||
|
||||
if err != nil {
|
||||
maxLength = limits.DefaultTextMaxLength
|
||||
}
|
||||
|
||||
b.WriteString(components.InputText(idPrefix+field.Name, fieldValue.String(), field.Name, field.Tag.Get("tooltip"), maxLength))
|
||||
}
|
||||
|
||||
if showPreview {
|
||||
|
Loading…
Reference in New Issue
Block a user