github.com/aldelo/common@v1.5.1/wrapper/gin/gintemplate.go (about)

     1  package gin
     2  
     3  /*
     4   * Copyright 2020-2023 Aldelo, LP
     5   *
     6   * Licensed under the Apache License, Version 2.0 (the "License");
     7   * you may not use this file except in compliance with the License.
     8   * You may obtain a copy of the License at
     9   *
    10   *     http://www.apache.org/licenses/LICENSE-2.0
    11   *
    12   * Unless required by applicable law or agreed to in writing, software
    13   * distributed under the License is distributed on an "AS IS" BASIS,
    14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    15   * See the License for the specific language governing permissions and
    16   * limitations under the License.
    17   */
    18  
    19  import (
    20  	"fmt"
    21  	util "github.com/aldelo/common"
    22  	"github.com/gin-contrib/multitemplate"
    23  	"path/filepath"
    24  )
    25  
    26  // NewTemplate creates new html template render worker object
    27  //
    28  // templateBaseDir = (required) base directory that contains template files
    29  // templateLayoutPath = (required) relative page layout folder path, layout defines site theme and common base pages
    30  //  1. to use page parts, use {{ template "xyz" }}
    31  //  2. see golang html page template rules for more information
    32  //
    33  // templatePagePath = (optional) relative page part folder path, pages define portion of html to be inserted into layout themes
    34  //  1. to define page part with named template, use {{ define "xyz" }}  {{ end }}
    35  //  2. see golang html page template rules for more information
    36  //
    37  // notes
    38  //  1. c.HTML name = page html name, such as home.html, if there is no page name, then use layout name
    39  //  2. if c.HTML name cannot find target in renderer, error 500 will be encountered
    40  //  3. layout file should not contain page parts may not be rendered in c.HTML call
    41  //  4. basic info about html templates = https://blog.gopheracademy.com/advent-2017/using-go-templates/
    42  func NewTemplate(templateBaseDir string, templateLayoutPath string, templatePagePath string) *GinTemplate {
    43  	return &GinTemplate{
    44  		TemplateBaseDir: templateBaseDir,
    45  		Templates: []TemplateDefinition{
    46  			{
    47  				LayoutPath: templateLayoutPath,
    48  				PagePath:   templatePagePath,
    49  			},
    50  		},
    51  	}
    52  }
    53  
    54  // GinTemplate defines the struct for working with html template renderer
    55  type GinTemplate struct {
    56  	TemplateBaseDir string
    57  	Templates       []TemplateDefinition
    58  
    59  	_htmlrenderer       multitemplate.Renderer
    60  	_htmlTemplatesCount int
    61  }
    62  
    63  // TemplateDefinition defines an unit of template render target
    64  type TemplateDefinition struct {
    65  	LayoutPath string
    66  	PagePath   string
    67  }
    68  
    69  // LoadHtmlTemplates will load html templates and set renderer into struct internal var
    70  func (t *GinTemplate) LoadHtmlTemplates() error {
    71  	t._htmlTemplatesCount = 0
    72  
    73  	if util.LenTrim(t.TemplateBaseDir) == 0 {
    74  		return fmt.Errorf("Html Template Base Dir is Required")
    75  	}
    76  
    77  	if len(t.Templates) == 0 {
    78  		return fmt.Errorf("Html Template Definition is Required")
    79  	}
    80  
    81  	r := multitemplate.NewRenderer()
    82  
    83  	if util.Right(t.TemplateBaseDir, 1) == "/" {
    84  		t.TemplateBaseDir = util.Left(t.TemplateBaseDir, len(t.TemplateBaseDir)-1)
    85  	}
    86  
    87  	for _, td := range t.Templates {
    88  		if util.LenTrim(td.LayoutPath) > 0 {
    89  			layout := td.LayoutPath
    90  			page := td.PagePath
    91  
    92  			if util.Left(layout, 1) != "/" {
    93  				layout = "/" + layout
    94  			}
    95  
    96  			if util.LenTrim(page) > 0 {
    97  				if util.Left(page, 1) != "/" {
    98  					page = "/" + page
    99  				}
   100  			}
   101  
   102  			// get all files matching layout pattern
   103  			layoutFiles, err := filepath.Glob(t.TemplateBaseDir + layout)
   104  
   105  			if err != nil {
   106  				continue
   107  			}
   108  
   109  			if len(layoutFiles) == 0 {
   110  				continue
   111  			}
   112  
   113  			if util.LenTrim(page) == 0 {
   114  				// only layout files to add to renderer
   115  				// template name is not important for 'AddFromFiles' (based on AddFromFiles source)
   116  				if tp := r.AddFromFiles(filepath.Base(layoutFiles[0]), layoutFiles...); tp != nil {
   117  					t._htmlTemplatesCount = len(layoutFiles)
   118  				}
   119  			} else {
   120  				// has layout and page files to add to renderer
   121  				pageFiles, err := filepath.Glob(t.TemplateBaseDir + page)
   122  
   123  				if err != nil {
   124  					continue
   125  				}
   126  
   127  				if len(pageFiles) == 0 {
   128  					continue
   129  				}
   130  
   131  				// layout with page files to add to renderer
   132  				// template name is not important for 'AddFromFiles' (based on AddFromFiles source)
   133  				for _, f := range pageFiles {
   134  					layoutCopy := make([]string, len(layoutFiles))
   135  					copy(layoutCopy, layoutFiles)
   136  					files := append(layoutCopy, f)
   137  
   138  					if tp := r.AddFromFiles(filepath.Base(f), files...); tp != nil {
   139  						t._htmlTemplatesCount++
   140  					}
   141  				}
   142  			}
   143  		}
   144  	}
   145  
   146  	if t._htmlTemplatesCount <= 0 {
   147  		t._htmlrenderer = nil
   148  		return fmt.Errorf("No Html Templates Loaded Into Renderer")
   149  	} else {
   150  		t._htmlrenderer = r
   151  		return nil
   152  	}
   153  }
   154  
   155  // SetHtmlRenderer will set the existing html renderer into gin engine's HTMLRender property
   156  func (t *GinTemplate) SetHtmlRenderer(g *Gin) error {
   157  	if t._htmlrenderer == nil {
   158  		return fmt.Errorf("Html Template Renderer is Required")
   159  	}
   160  
   161  	if g == nil {
   162  		return fmt.Errorf("Gin Wrapper is Required")
   163  	}
   164  
   165  	if g._ginEngine == nil {
   166  		return fmt.Errorf(("Gin Engine is Required"))
   167  	}
   168  
   169  	if t._htmlTemplatesCount <= 0 {
   170  		return fmt.Errorf("No Html Templates Loaded Into Renderer")
   171  	}
   172  
   173  	if t._htmlrenderer == nil {
   174  		return fmt.Errorf("Html Renderer Must Not Be Nil")
   175  	}
   176  
   177  	g._ginEngine.HTMLRender = t._htmlrenderer
   178  	return nil
   179  }