go.charczuk.com@v0.0.0-20240327042549-bc490516bd1a/projects/blogctl/pkg/engine/template.go (about)

     1  /*
     2  
     3  Copyright (c) 2023 - Present. Will Charczuk. All rights reserved.
     4  Use of this source code is governed by a MIT license that can be found in the LICENSE file at the root of the repository.
     5  
     6  */
     7  
     8  package engine
     9  
    10  import (
    11  	"bytes"
    12  	"errors"
    13  	"fmt"
    14  	"html/template"
    15  
    16  	"go.charczuk.com/sdk/viewutil"
    17  
    18  	"go.charczuk.com/projects/blogctl/pkg/model"
    19  )
    20  
    21  // ViewFuncs is the template funcs.
    22  func ViewFuncs() template.FuncMap {
    23  	base := viewutil.Funcs
    24  	base["partition"] = partition
    25  	base["set_title"] = setTitle
    26  	base["render_post"] = renderPost
    27  	return template.FuncMap(base)
    28  }
    29  
    30  // ParseTemplate creates a new template from a string
    31  func ParseTemplate(literal string) (*template.Template, error) {
    32  	tmp := template.New("")
    33  	tmp.Funcs(ViewFuncs())
    34  	return tmp.Parse(literal)
    35  }
    36  
    37  // RenderString renders a template to a string for a given viewmodel.
    38  func RenderString(tmp *template.Template, vm interface{}) (string, error) {
    39  	buffer := new(bytes.Buffer)
    40  	if err := tmp.Execute(buffer, vm); err != nil {
    41  		return "", err
    42  	}
    43  	return buffer.String(), nil
    44  }
    45  
    46  // Partition Errors
    47  var (
    48  	ErrPartitionCountTooLarge = errors.New("partition count greater than number of posts")
    49  	ErrPartitionIndexTooLarge = errors.New("partition index greater than number of partitions")
    50  	ErrPartitionCountInvalid  = errors.New("partition count invalid; must be greater than 1")
    51  )
    52  
    53  func partition(index, partitions int, posts []*model.Post) ([]*model.Post, error) {
    54  	if partitions < 1 {
    55  		return nil, ErrPartitionCountInvalid
    56  	}
    57  	if index < 0 || index >= partitions {
    58  		return nil, ErrPartitionIndexTooLarge
    59  	}
    60  	if partitions == 1 {
    61  		return posts, nil
    62  	}
    63  
    64  	var output []*model.Post
    65  	for ; index < len(posts); index += partitions {
    66  		output = append(output, posts[index])
    67  	}
    68  	return output, nil
    69  }
    70  
    71  func setTitle(vm *model.ViewModel, title string) error {
    72  	if vm == nil {
    73  		return fmt.Errorf("viewmodel unset")
    74  	}
    75  	vm.Title = title
    76  	return nil
    77  }
    78  
    79  func renderPost(post model.Post) (template.HTML, error) {
    80  	if post.Template == nil {
    81  		return "", fmt.Errorf("post has unset template; cannot render. post: %s", post.TitleOrDefault())
    82  	}
    83  	buffer := new(bytes.Buffer)
    84  	err := post.Template.Execute(buffer, post)
    85  	if err != nil {
    86  		return "", err
    87  	}
    88  	return template.HTML(buffer.String()), nil
    89  }