package gallery import ( "sort" "strings" "amadan.net/rastrillo/fiesta" ) // formerRTL is the directory a theme's right-to-left twin had before // every page moved under a locale: /rtl/, beside the // English /. Those addresses were published, so they are // redirected rather than left to 404. const formerRTL = "rtl" // Redirects are the _redirects rules, for a tree rendered for mount, // that send each address the gallery had before its pages moved under // a locale to the page that is there now, with a 301: // // / /en/ // /index.html /en/ // /.html /en/.html // /frames// /en/frames// // /rtl/... the same under /ar/ // // An index goes to its directory, the address the edge serves it at, // since the edge sends .../index.html on to ./ and that would be a // second hop. The rules are written so that no source can match a // file of the tree, and no destination can match a source, so none // shadows a page and none leads to another: every file of today's tree // sits under // or assets/, and no locale is "frames", // "rtl", "index.html" or a page's name. So /rtl/:page can be one // rule, but an English page is named rule by rule: /:page would // also match /en, the English tree's own directory. The pages // named are the ones tree holds at /en/ in every theme, so each // destination is a page whatever the theme. The order is fixed, so the // same tree gives the same rules. func Redirects(mount string, tree map[string][]byte) []string { m := cleanMount(mount) en, ar := Locales[0], rtlLocale() var out []string rule := func(from, to string) { out = append(out, m+from+" "+m+to+" 301") } themes := fiesta.ThemeNames() for _, theme := range themes { rule("/"+theme, "/"+theme+"/"+en+"/") } rule("/:theme/index.html", "/:theme/"+en+"/") rule("/:theme/frames/:example/:state", "/:theme/"+en+"/frames/:example/:state") for _, page := range everyThemesPages(tree, themes, en) { rule("/:theme/"+page, "/:theme/"+en+"/"+page) } twin := "/:theme/" + formerRTL rule(twin, "/:theme/"+ar+"/") rule(twin+"/index.html", "/:theme/"+ar+"/") rule(twin+"/frames/:example/:state", "/:theme/"+ar+"/frames/:example/:state") rule(twin+"/:page", "/:theme/"+ar+"/:page") return out } // rtlLocale is the locale that renders right to left, where the former // twins now live. func rtlLocale() string { for _, l := range Locales { if Dir(l) == "rtl" { return l } } panic("gallery: no locale renders right to left") } // everyThemesPages are the names of the HTML pages directly under // // for every theme, the index aside, sorted. func everyThemesPages(tree map[string][]byte, themes []string, locale string) []string { count := map[string]int{} for name := range tree { for _, theme := range themes { page, ok := strings.CutPrefix(name, theme+"/"+locale+"/") if ok && !strings.Contains(page, "/") && strings.HasSuffix(page, ".html") && page != "index.html" { count[page]++ } } } var pages []string for page, n := range count { if n == len(themes) { pages = append(pages, page) } } sort.Strings(pages) return pages }