func PrapareWidgets(widgets []Widget, mapper Mapper, topCtx mustache.Context) mustache.Context { mappers := make([]interface{}, 0) for _, widget := range widgets { mr := widget.Prepare(mapper, topCtx) if mr != nil { mappers = append(mappers, mr) } } return mustache.MakeContexts(mappers...) }
func RenderInLayout(content string, layoutName string, layouts map[string]Mapper, ctx mustache.Context) (string, error) { //log.Println("Render Layout", layoutName, ">>", content, "<<END") ctx2 := make(map[string]string) ctx2["content"] = content layout := layouts[layoutName] //log.Println(layoutName, layout["_content"]) buf := &bytes.Buffer{} err := layout["_content"].(*DocContent).TPL.Render(mustache.MakeContexts(ctx2, ctx), buf) if err != nil { return content, err } if layout.Layout() != "" { return RenderInLayout(buf.String(), layout.Layout(), layouts, ctx) } return buf.String(), nil }
func RenderInLayout(content string, layoutName string, layouts map[string]Mapper, ctx mustache.Context) (string, error) { Log(DEBUG, "Render layout %q >>\n%s\nEOF\n", layoutName, content) ctx2 := make(map[string]string) ctx2["content"] = content layout := layouts[layoutName] if layout == nil { errMsg := fmt.Sprintf("Not found %s layout", layoutName) return "", errors.New(errMsg) } if c, ok := layout["_content"].(string); ok { Log(DEBUG, "Layout %q >>\n%s\nEOF", layoutName, c) } buf := &bytes.Buffer{} err := layout["_content"].(*DocContent).TPL.Render(mustache.MakeContexts(ctx2, ctx), buf) if err != nil { return content, err } if layout.Layout() != "" { return RenderInLayout(buf.String(), layout.Layout(), layouts, ctx) } return buf.String(), nil }
func renderPaginator(pgCnf Mapper, layouts map[string]Mapper, topCtx mustache.Context, widgets []Widget) { summary_lines := int(FromCtx(topCtx, "site.config.posts.summary_lines").(int64)) per_page := pgCnf.Int("per_page") if per_page < 2 { per_page = 2 } else if per_page > 100 { per_page = 100 } namespace := pgCnf.String("namespace") if namespace == "" { namespace = "/posts/" } layout := pgCnf.String("layout") posts_ctx := make(Mapper) chronological, _ := FromCtx(topCtx, "db.posts.chronological").([]string) dictionary, _ := FromCtx(topCtx, "db.posts.dictionary").(map[string]Mapper) page_count := len(chronological)/per_page + 1 if len(chronological)%per_page == 0 { page_count-- } paginator_navigation := make([]Mapper, page_count) for i := 0; i < len(paginator_navigation); i++ { pn := make(Mapper) pn["page_number"] = i + 1 pn["name"] = fmt.Sprintf("%d", i+1) pn["url"] = fmt.Sprintf("%s%d/", namespace, i+1) pn["is_active_page"] = false paginator_navigation[i] = pn } posts_ctx["paginator_navigation"] = paginator_navigation one_page := make([]Mapper, 0) current_page_number := 0 log.Println("Total posts: ", len(chronological)) for i, post_id := range chronological { if i != 0 && i%per_page == 0 { current_page_number++ log.Printf("Rendering page #%d with %d posts", current_page_number, len(one_page)) posts_ctx["current_page_number"] = current_page_number posts_ctx["paginator"] = one_page if current_page_number >= 2 { paginator_navigation[current_page_number-2]["is_active_page"] = false } paginator_navigation[current_page_number-1]["is_active_page"] = true widgetCtx := PrapareWidgets(widgets, make(Mapper), topCtx) renderOnePager(paginator_navigation[current_page_number-1].String("url"), layout, layouts, mustache.MakeContexts(map[string]interface{}{"posts": posts_ctx, "page": map[string]interface{}{}}, topCtx, widgetCtx)) one_page = one_page[0:0] } post := dictionary[post_id] post["summary"] = MakeSummary(post, summary_lines, topCtx) one_page = append(one_page, post) } if len(one_page) > 0 { current_page_number++ log.Printf("Rendering page #%d with %d post(s)", current_page_number, len(one_page)) posts_ctx["current_page_number"] = current_page_number posts_ctx["paginator"] = one_page if current_page_number >= 2 { paginator_navigation[current_page_number-2]["is_active_page"] = false } paginator_navigation[current_page_number-1]["is_active_page"] = true m := make(Mapper) widgetCtx := PrapareWidgets(widgets, m, topCtx) renderOnePager(paginator_navigation[current_page_number-1].String("url"), layout, layouts, mustache.MakeContexts(map[string]interface{}{"posts": posts_ctx, "page": map[string]interface{}{}}, topCtx, widgetCtx)) } }
// 编译整个网站 func Compile() error { var ctx mustache.Context // 渲染上下文 var docCont *DocContent // 文档内容,仅作为变量声明 var str string // 仅声明,以减少不一样的编译错误 var err error // 仅声明 var layouts map[string]Mapper payload, err := BuildPlayload("./") // payload,核心上下文的主要部分,不可变 if err != nil { log.Println("Build PayLoad FAIL!!") return err } payload_ctx := mustache.MakeContextDir(payload, ".tmp_partials/") themeName := FromCtx(payload_ctx, "site.config.theme").(string) if FromCtx(payload_ctx, "site.config.markdown.toc_title") != nil { TOC_TITLE = FromCtx(payload_ctx, "site.config.markdown.toc_title").(string) } os.Remove(".tmp_partials") copyDir("partials", ".tmp_partials") copyDir("themes/"+themeName+"/partials", ".tmp_partials") db_posts_dict, _ := payload_ctx.Get("db.posts.dictionary") //log.Println(">>>>>>>>>>>>", len(db_posts_dict.Val.Interface().(map[string]Mapper))) for id, post := range db_posts_dict.Val.Interface().(map[string]Mapper) { _tmp, err := PrapreMainContent(id, post["_content"].(*DocContent).Source, payload_ctx) if err != nil { return err } post["_content"].(*DocContent).Main = _tmp //log.Fatal(_tmp) } //mdParser = markdown.NewParser(&markdown.Extensions{Smart: true}) helpers := make(map[string]mustache.SectionRenderFunc) ctxHelpers := make(map[string]func(interface{}) interface{}) dynamicMapper := make(Mapper) topCtx := mustache.MakeContexts(payload_ctx, helpers, ctxHelpers, dynamicMapper) widgets, widget_assets, err := LoadWidgets(topCtx) if err != nil { return err } //log.Println(">>>", payload_ctx.Dir(), "?>", topCtx.Dir()) BaiscHelpers(payload, helpers, topCtx) CtxHelpers(payload, ctxHelpers, topCtx) layouts = payload["layouts"].(map[string]Mapper) if len(widgets) > 0 { widget_assets += PrapareAssets(themeName, "widgets", topCtx) } CopyResources(themeName) // Render Pages pages := payload["db"].(map[string]interface{})["pages"].(map[string]Mapper) for id, page := range pages { docCont = page["_content"].(*DocContent) //top := make(map[string]interface{}) dynamicMapper["current_page_id"] = id dynamicMapper["page"] = page dynamicMapper["assets"] = PrapareAssets(themeName, page.Layout(), topCtx) + widget_assets widgetCtx := PrapareWidgets(widgets, page, topCtx) ctx = mustache.MakeContexts(page, dynamicMapper, topCtx, widgetCtx) //log.Println(">>", ctx.Dir(), topCtx.Dir()) _tmp, err := PrapreMainContent(id, docCont.Source, ctx) if err != nil { return err } page["_content"].(*DocContent).Main = _tmp str, err = RenderInLayout(docCont.Main, page.Layout(), layouts, ctx) if err != nil { return errors.New(id + ">" + err.Error()) } WriteTo(page.Url(), str) } // Render Posts for id, post := range db_posts_dict.Val.Interface().(map[string]Mapper) { //top := make(map[string]interface{}) dynamicMapper["current_page_id"] = id dynamicMapper["page"] = post dynamicMapper["assets"] = PrapareAssets(themeName, post.Layout(), topCtx) + widget_assets docCont = post["_content"].(*DocContent) widgetCtx := PrapareWidgets(widgets, post, topCtx) ctx = mustache.MakeContexts(post, dynamicMapper, topCtx, widgetCtx) str, err = RenderInLayout(docCont.Main, post.Layout(), layouts, ctx) if err != nil { return errors.New(id + ">" + err.Error()) } WriteTo(post.Url(), str) } //我们还得把分页给解决了哦 if paginatorCnf := FromCtx(topCtx, "site.config.paginator"); paginatorCnf != nil { var pgCnf Mapper pgCnf = paginatorCnf.(map[string]interface{}) if _, ok := layouts[pgCnf.String("layout")]; ok { log.Println("Enable paginator") renderPaginator(pgCnf, layouts, topCtx, widgets) } else { log.Println("Layout Not Found", pgCnf.String("layout")) } } if Plugins != nil { for _, plugin := range Plugins { plugin.Exec(topCtx) } } log.Println("Done") return nil }
func BaiscHelpers(payload Mapper, helpers map[string]mustache.SectionRenderFunc, topCtx mustache.Context) { var err error chronological := FromCtx(topCtx, "db.posts.chronological").([]string) latest_size := FromCtx(topCtx, "site.config.posts.latest").(int) dict := FromCtx(topCtx, "db.posts.dictionary").(map[string]Mapper) summary_lines := int(FromCtx(topCtx, "site.config.posts.summary_lines").(int64)) latest_posts := make([]Mapper, 0) for _, id := range chronological { latest_posts = append(latest_posts, dict[id]) if len(latest_posts) >= latest_size { break } } //------------------------------- helpers["posts_latest"] = func(nodes []mustache.Node, inverted bool, ctx mustache.Context, w io.Writer) error { if inverted { return nil } for _, post := range latest_posts { top := map[string]interface{}{} top["summary"] = MakeSummary(post, summary_lines, topCtx) //log.Println(top["summary"]) top["content"] = post["_content"].(*DocContent).Main for _, node := range nodes { err = node.Render(mustache.MakeContexts(post, top, ctx), w) if err != nil { return err } } } return nil } pages := FromCtx(topCtx, "db.pages").(map[string]Mapper) helpers["pages"] = func(nodes []mustache.Node, inverted bool, ctx mustache.Context, w io.Writer) error { if inverted { return nil } current_page_id := FromCtx(ctx, "current_page_id") for id, page := range pages { top := map[string]interface{}{} if current_page_id != nil { top["is_active_page"] = id == current_page_id.(string) } for _, node := range nodes { err = node.Render(mustache.MakeContexts(page, top, ctx), w) if err != nil { return err } } } return nil } helpers["posts"] = func(nodes []mustache.Node, inverted bool, ctx mustache.Context, w io.Writer) error { if inverted { return nil } for _, post := range dict { for _, node := range nodes { err = node.Render(mustache.MakeContexts(post, ctx), w) if err != nil { return err } } } return nil } categories := FromCtx(topCtx, "db.posts.categories").(map[string]*Catalog) helpers["categories"] = func(nodes []mustache.Node, inverted bool, ctx mustache.Context, w io.Writer) error { if inverted { return nil } //log.Println("Using #categories") for _, categorie := range categories { for _, node := range nodes { err = node.Render(mustache.MakeContexts(categorie, ctx), w) if err != nil { return err } } } return nil } tags := FromCtx(topCtx, "db.posts.tags").(map[string]*Tag) helpers["tags"] = func(nodes []mustache.Node, inverted bool, ctx mustache.Context, w io.Writer) error { if inverted { return nil } for _, tag := range tags { for _, node := range nodes { err = node.Render(mustache.MakeContexts(tag, ctx), w) if err != nil { return err } } } return nil } return }
func Compile() error { var payload Mapper var ctx mustache.Context var docCont *DocContent //var tpl *mustache.Template var str string var err error //var mdParser *markdown.Parser //var buf *bytes.Buffer var layouts map[string]Mapper payload, err = BuildPlayload() if err != nil { return err } payload_ctx := mustache.MakeContextDir(payload, "partials/") db_posts_dict, _ := payload_ctx.Get("db.posts.dictionary") //log.Println(">>>>>>>>>>>>", len(db_posts_dict.Val.Interface().(map[string]Mapper))) for id, post := range db_posts_dict.Val.Interface().(map[string]Mapper) { _tmp, err := PrapreMainContent(id, post["_content"].(*DocContent).Source, payload_ctx) if err != nil { return err } post["_content"].(*DocContent).Main = _tmp //log.Fatal(_tmp) } themeName := FromCtx(payload_ctx, "site.config.theme").(string) //mdParser = markdown.NewParser(&markdown.Extensions{Smart: true}) helpers := make(map[string]mustache.SectionRenderFunc) ctxHelpers := make(map[string]func(interface{}) interface{}) dynamicCtx := make(Mapper) topCtx := mustache.MakeContexts(payload_ctx, helpers, ctxHelpers, map[string]Mapper{"dynamic": dynamicCtx}) widgets, err := LoadWidgets(topCtx) if err != nil { return err } //log.Println(">>>", payload_ctx.Dir(), "?>", topCtx.Dir()) BaiscHelpers(payload, helpers, topCtx) CtxHelpers(payload, ctxHelpers, topCtx) layouts = payload["layouts"].(map[string]Mapper) widget_assets := "" if len(widgets) > 0 { widget_assets = PrapareAssets(themeName, "widgets", topCtx) } CopyResources(themeName) // Render Pages pages := payload["db"].(map[string]interface{})["pages"].(map[string]Mapper) for id, page := range pages { docCont = page["_content"].(*DocContent) top := make(map[string]interface{}) top["current_page_id"] = id top["page"] = page top["assets"] = PrapareAssets(themeName, page.Layout(), topCtx) + widget_assets widgetCtx := PrapareWidgets(widgets, page, topCtx) ctx = mustache.MakeContexts(page, top, topCtx, widgetCtx) //log.Println(">>", ctx.Dir(), topCtx.Dir()) _tmp, err := PrapreMainContent(id, docCont.Source, ctx) if err != nil { return err } page["_content"].(*DocContent).Main = _tmp str, err = RenderInLayout(docCont.Main, page.Layout(), layouts, ctx) if err != nil { return errors.New(id + ">" + err.Error()) } WriteTo(page.Url(), str) } // Render Posts for id, post := range db_posts_dict.Val.Interface().(map[string]Mapper) { top := make(map[string]interface{}) top["current_page_id"] = id top["page"] = post top["assets"] = PrapareAssets(themeName, post.Layout(), topCtx) + widget_assets docCont = post["_content"].(*DocContent) widgetCtx := PrapareWidgets(widgets, post, topCtx) ctx = mustache.MakeContexts(post, top, topCtx, widgetCtx) str, err = RenderInLayout(docCont.Main, post.Layout(), layouts, ctx) if err != nil { return errors.New(id + ">" + err.Error()) } WriteTo(post.Url(), str) } if Plugins != nil { for _, plugin := range Plugins { plugin.Exec(topCtx) } } log.Println("Done") return nil }
// 编译整个网站 func Compile(public string) error { var ctx mustache.Context // 渲染上下文 var docCont *DocContent // 文档内容,仅作为变量声明 var str string // 仅声明,以减少不一样的编译错误 var err error // 仅声明 var layouts map[string]Mapper payload, err := BuildPayload("./") // payload,核心上下文的主要部分,不可变 if err != nil { Log(INFO, "Build payload fail, %s!!", err) return err } payload_ctx := mustache.MakeContextDir(payload, ".tmp_partials/") themeName := FromCtx(payload_ctx, "site.config.theme").(string) if FromCtx(payload_ctx, "site.config.markdown.toc_title") != nil { TOC_TITLE = FromCtx(payload_ctx, "site.config.markdown.toc_title").(string) } os.Remove(".tmp_partials") copyDir("partials", ".tmp_partials") theme_partials := filepath.Join("themes/", themeName, "/partials") if fi, err := os.Stat(theme_partials); err == nil && fi.IsDir() { copyDir(theme_partials, ".tmp_partials") } defer os.Remove(".tmp_partials") db_posts_dict, _ := payload_ctx.Get("db.posts.dictionary") Log(DEBUG, "Total of db posts dictionary: %d", len(db_posts_dict.Val.Interface().(map[string]Mapper))) for id, post := range db_posts_dict.Val.Interface().(map[string]Mapper) { _tmp, err := PrapreMainContent(id, post["_content"].(*DocContent).Source, payload_ctx) if err != nil { return err } post["_content"].(*DocContent).Main = _tmp Log(DEBUG, "Markdown to HTML: \n%s\n", _tmp) } helpers := make(map[string]mustache.SectionRenderFunc) ctxHelpers := make(map[string]func(interface{}) interface{}) dynamicMapper := make(Mapper) topCtx := mustache.MakeContexts(payload_ctx, helpers, ctxHelpers, dynamicMapper) widgets, widget_assets, err := LoadWidgets(topCtx) if err != nil { return err } Log(DEBUG, payload_ctx.Dir(), "?>", topCtx.Dir()) BaiscHelpers(payload, helpers, topCtx) CtxHelpers(payload, ctxHelpers, topCtx) layouts = payload["layouts"].(map[string]Mapper) if len(widgets) > 0 { widget_assets += PrapareAssets(themeName, "widgets", topCtx) } CopyResources(public, themeName) // Render Pages pages := payload["db"].(map[string]interface{})["pages"].(map[string]Mapper) for id, page := range pages { docCont = page["_content"].(*DocContent) //top := make(map[string]interface{}) dynamicMapper["current_page_id"] = id dynamicMapper["page"] = page dynamicMapper["assets"] = PrapareAssets(themeName, page.Layout(), topCtx) + widget_assets widgetCtx := PrapareWidgets(widgets, page, topCtx) ctx = mustache.MakeContexts(page, dynamicMapper, topCtx, widgetCtx) //Log(DEBUG, "%s %s", ctx.Dir(), topCtx.Dir()) _tmp, err := PrapreMainContent(id, docCont.Source, ctx) if err != nil { return err } page["_content"].(*DocContent).Main = _tmp str, err = RenderInLayout(docCont.Main, page.Layout(), layouts, ctx) if err != nil { return errors.New(fmt.Sprintf("Page %d > %s", id, err.Error())) } WriteTo(public, page.Url(), str) } // Render Posts for id, post := range db_posts_dict.Val.Interface().(map[string]Mapper) { //top := make(map[string]interface{}) dynamicMapper["current_page_id"] = id dynamicMapper["page"] = post dynamicMapper["assets"] = PrapareAssets(themeName, post.Layout(), topCtx) + widget_assets docCont = post["_content"].(*DocContent) widgetCtx := PrapareWidgets(widgets, post, topCtx) ctx = mustache.MakeContexts(post, dynamicMapper, topCtx, widgetCtx) str, err = RenderInLayout(docCont.Main, post.Layout(), layouts, ctx) if err != nil { return errors.New(fmt.Sprintf("Post %d > %s", id, err.Error())) } WriteTo(public, post.Url(), str) } //我们还得把分页给解决了哦 if paginatorCnf := FromCtx(topCtx, "site.config.paginator"); paginatorCnf != nil { var pgCnf Mapper pgCnf = paginatorCnf.(map[string]interface{}) if _, ok := layouts[pgCnf.String("layout")]; ok { Log(INFO, "Enable paginator") renderPaginator(public, pgCnf, layouts, topCtx, widgets) } else { Log(INFO, "Layout Not Found", pgCnf.String("layout")) } } if Plugins != nil { for _, plugin := range Plugins { plugin.Exec(public, topCtx) } } Log(INFO, "Done") return nil }