func ArticleHandler(ctx *app.Context) { slug := ctx.IndexValue(0) var art *article.Article articles := getArticles(ctx) for _, v := range articles { if v.Slug() == slug { art = v break } } if art == nil { for _, v := range articles { for _, s := range v.AllSlugs() { if s == slug { ctx.MustRedirectReverse(true, ctx.HandlerName(), s) return } } } ctx.NotFound("article not found") return } fs := vfs.Memory() filename := path.Base(art.Filename) if filename == "" { filename = "article.html" } if err := vfs.WriteFile(fs, filename, art.Text, 0644); err != nil { panic(err) } log.Debugf("loading article %s", articleId(art)) tmpl, err := app.LoadTemplate(ctx.App(), fs, nil, filename) if err != nil { panic(err) } var buf bytes.Buffer if err := tmpl.ExecuteTo(&buf, ctx, nil); err != nil { panic(err) } body := buf.String() data := map[string]interface{}{ "Article": art, "Title": art.Title(), "Body": template.HTML(body), } ctx.MustExecute("article.html", data) }
func UserImageHandler(ctx *app.Context) { if ImageHandler != nil { ImageHandler(ctx) return } id := ctx.IndexValue(0) format := ctx.IndexValue(1) if lower := strings.ToLower(format); lower != format { ctx.MustRedirectReverse(true, ImageHandlerName, id, lower) return } ctx.SetHeader("Content-Type", "image/"+format) httpserve.NeverExpires(ctx) bs := ctx.Blobstore() if err := bs.Serve(ctx, id, nil); err != nil { panic(err) } }
// NewPager returns a new *Pager instance. Note that the // Context must satisfy the conditions mentioned in the // Pager type documentation. Otherwise an error will be // returned. func NewPager(ctx *app.Context) (*Pager, error) { name := ctx.HandlerName() if name == "" { return nil, errors.New("can't generate a pager from an unnamed handler") } names := ctx.Provider().ParamNames() if len(names) == 0 { return nil, errors.New("can't generate a pager from a handler with no parameters, must have a page parameter") } if names[len(names)-1] != "page" { return nil, fmt.Errorf("last named parameter is %q, not page", names[len(names)-1]) } params := make([]interface{}, ctx.Count()-1) for ii := 0; ii < ctx.Count()-1; ii++ { params[ii] = ctx.IndexValue(ii) } return &Pager{ Name: name, Parameters: params, Ctx: ctx, }, nil }
func PackageHandler(ctx *app.Context) { dctx := getEnvironment(ctx) rel := ctx.IndexValue(0) if rel[len(rel)-1] == '/' { ctx.MustRedirectReverse(true, PackageHandlerName, rel[:len(rel)-1]) return } pkg, err := dctx.ImportPackage(rel) if err != nil { panic(err) } var title string var header string var distinct bool switch { case pkg.IsMain(): title = "Command " + path.Base(rel) header = title case pkg.IsEmpty(): prefix := "Directory " header = prefix + path.Base(rel) if pkg.ImportPath() != "" { title = prefix + pkg.ImportPath() } else { title = header } default: title = "Package " + pkg.ImportPath() header = "Package " + pkg.Name() distinct = path.Base(pkg.ImportPath()) != pkg.Name() } breadcrumbs := []*breadcrumb{ {Title: "Index", Href: ctx.MustReverse(ListHandlerName)}, } if pkg.IsStd() { breadcrumbs = append(breadcrumbs, &breadcrumb{ Title: "std", Href: ctx.MustReverse(PackageHandlerName, "std"), }) } for ii := 0; ii < len(rel); { var end int slash := strings.IndexByte(rel[ii:], '/') if slash < 0 { end = len(rel) } else { end = ii + slash } breadcrumbs = append(breadcrumbs, &breadcrumb{ Title: rel[ii:end], Href: ctx.MustReverse(PackageHandlerName, rel[:end]), }) ii = end + 1 } data := map[string]interface{}{ "Header": header, "Title": title, "Breadcrumbs": breadcrumbs, "Package": pkg, "Distinct": distinct, } ctx.MustExecute("package.html", data) }
func SourceHandler(ctx *app.Context) { dctx := doc.GetEnvironment(ctx.App()) rel := ctx.IndexValue(0) p := dctx.FromSlash(rel) pDir := dctx.Dir(p) if pDir == "." { pDir = p } else { } dir := packageDir(dctx, pDir) filePath := dir if pDir+dctx.Separator != p && pDir != p { filePath = dctx.Join(dir, dctx.Base(p)) } log.Debugf("Loading source from %s", filePath) var breadcrumbs []*breadcrumb for ii := 0; ii < len(rel); { var end int slash := strings.IndexByte(rel[ii:], '/') if slash < 0 { end = len(rel) } else { end = ii + slash } breadcrumbs = append(breadcrumbs, &breadcrumb{ Title: rel[ii:end], Href: ctx.MustReverse(SourceHandlerName, rel[:end]), }) ii = end + 1 } var tmpl string var title string var files []string var code template.HTML var lines []int if dctx.IsDir(filePath) { if rel != "" && rel[len(rel)-1] != '/' { ctx.MustRedirectReverse(true, SourceHandlerName, rel+"/") return } contents, err := dctx.ReadDir(filePath) if err != nil { panic(err) } for _, v := range contents { if n := v.Name(); len(n) > 0 && n[0] != '.' { files = append(files, n) } } title = "Directory " + dctx.Base(rel) tmpl = "dir.html" } else { f, err := dctx.OpenFile(filePath) if err != nil { ctx.NotFound("File not found") return } defer f.Close() contents, err := ioutil.ReadAll(f) if err != nil { panic(err) } contentType := http.DetectContentType(contents) if !strings.HasPrefix(contentType, "text") { ctx.Header().Set("Content-Type", contentType) switch contentType { case "image/gif", "image/png", "image/jpeg": default: ctx.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%s;", dctx.Base(rel))) } ctx.Write(contents) return } title = "File " + dctx.Base(rel) var buf bytes.Buffer buf.WriteString("<span id=\"line-1\">") last := 0 line := 1 for ii, v := range contents { if v == '\n' { buf.WriteString(html.Escape(string(contents[last:ii]))) lines = append(lines, line) last = ii line++ buf.WriteString(fmt.Sprintf("</span><span id=\"line-%d\">", line)) } } buf.Write(contents[last:]) buf.WriteString("</span>") code = template.HTML(buf.String()) tmpl = "source.html" } data := map[string]interface{}{ "Title": rel, "Header": title, "Breadcrumbs": breadcrumbs, "Files": files, "Code": code, "Lines": lines, "Padding": math.Ceil(math.Log10(float64(len(lines)+1))) + 0.1, "Highlighter": highlighters[path.Ext(rel)], } ctx.MustExecute(tmpl, data) }