package helper import ( "errors" "fmt" "io/ioutil" "path" "strconv" "strings" "github.com/ddliu/motto" "github.com/disintegration/imaging" "github.com/flosch/pongo2" _ "github.com/flosch/pongo2-addons" _ "github.com/robertkrimen/otto/underscore" ) func init() { err := pongo2.ReplaceFilter("markdown", MarkdownFilter) if err != nil { panic(err) } newFilters := map[string]pongo2.FilterFunction{ "image_resize": ImageResizeFilter, "relative_path": RelativePathFilter, } for name, fn := range newFilters { err := pongo2.RegisterFilter(name, fn) if err != nil { panic(err) } } } // MarkdownFilter is a pongo2 filter, which converts markdown to html func MarkdownFilter(in *pongo2.Value, param *pongo2.Value) (*pongo2.Value, *pongo2.Error) { return pongo2.AsSafeValue( string( renderMarkdown( []byte(in.String()), currentPathConfig.Markdown, ))), nil } type imageParams struct { width int height int filename string } func parseImageParams(str string) (*imageParams, error) { if str == "" { return nil, errors.New("missing image parameters") } p := imageParams{} for _, s := range strings.Split(str, ",") { e := strings.Split(s, "=") if len(e) < 2 { return nil, fmt.Errorf("invalid image parameter: %s", s) } var err error switch e[0] { case "w": p.width, err = strconv.Atoi(e[1]) case "h": p.height, err = strconv.Atoi(e[1]) case "f": p.filename = e[1] default: return nil, fmt.Errorf("invalid image parameter: %s", s) } if err != nil { return nil, fmt.Errorf("could not convert image parameter to correct value type for '%s': %s", s, err) } } return &p, nil } // ImageResizeFilter read the image url and resize parameters and saves the resized image // param: w=WITDH,h=HEIGHT func ImageResizeFilter(in *pongo2.Value, param *pongo2.Value) (*pongo2.Value, *pongo2.Error) { imgSource := in.String() p, err := parseImageParams(param.String()) if err != nil { return nil, &pongo2.Error{ Sender: "filter:image_resize", OrigError: err, } } imgSource = ResolveInputPath(imgSource) if p.filename == "" { p.filename = fmt.Sprintf("%dx%d_%s", p.width, p.height, path.Base(imgSource)) } imgTarget := ResolveOutputPath(p.filename) Log.Noticef("resizing image from %s to %s", imgSource, imgTarget) img, err := imaging.Open(imgSource, imaging.AutoOrientation(true)) if err != nil { return nil, &pongo2.Error{ Sender: "filter:image_resize", OrigError: fmt.Errorf("could not open image '%s': %s", imgSource, err), } } img = imaging.Resize(img, p.width, p.height, imaging.Lanczos) err = imaging.Save(img, imgTarget) if err != nil { return nil, &pongo2.Error{ Sender: "filter:image_resize", OrigError: fmt.Errorf("could save image '%s': %s", imgTarget, err), } } return pongo2.AsValue(ResolveNavPath(p.filename)), nil } // RelativePathFilter returns the relative path to navpoint based on current nav func RelativePathFilter(in, param *pongo2.Value) (*pongo2.Value, *pongo2.Error) { return pongo2.AsValue( ResolveNavPath( in.String(), ), ), nil } // RegisterFilters reads a directory and register filters from files within it func RegisterFilters(dir string) { files, err := ioutil.ReadDir(dir) if err != nil { Log.Panicf("could not read from template filters dir '%s': %s", dir, err) } for _, f := range files { if !f.IsDir() { switch path.Ext(f.Name()) { case ".js": fileBase := strings.TrimSuffix(f.Name(), ".js") jsFile := dir + "/" + f.Name() Log.Debugf("trying to register filter from: %s", jsFile) /* jsStr, err := ioutil.ReadFile(jsFile) if err != nil { Log.Panicf("could not read '%s': %s", jsFile, err) } */ vm := motto.New() fn, err := vm.Run(jsFile) if err != nil { Log.Panicf("error in javascript vm for '%s': %s", jsFile, err) } if !fn.IsFunction() { Log.Panicf("%s does not contain a function code", jsFile) } err = pongo2.RegisterFilter( fileBase, func(in, param *pongo2.Value) (out *pongo2.Value, erro *pongo2.Error) { thisObj, _ := vm.Object("({})") if currentContext != nil { thisObj.Set("context", *currentContext) } if err != nil { Log.Panicf("could not set context as in '%s': %s", jsFile, err) } ret, err := fn.Call(thisObj.Value(), in.Interface(), param.Interface()) if err != nil { Log.Panicf("error in javascript file '%s' while calling returned function: %s", jsFile, err) } retGo, err := ret.Export() if err != nil { Log.Panicf("export error for '%s': %s", jsFile, err) } return pongo2.AsValue(retGo), nil }, ) if err != nil { Log.Panicf("could not register filter from '%s': %s", jsFile, err) } } } } }