gview.go 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. // Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
  2. //
  3. // This Source Code Form is subject to the terms of the MIT License.
  4. // If a copy of the MIT was not distributed with this file,
  5. // You can obtain one at https://github.com/gogf/gf.
  6. // Package gview implements a template engine based on text/template.
  7. //
  8. // Reserved template variable names:
  9. // I18nLanguage: Assign this variable to define i18n language for each page.
  10. package gview
  11. import (
  12. "context"
  13. "github.com/gogf/gf/v2"
  14. "github.com/gogf/gf/v2/container/garray"
  15. "github.com/gogf/gf/v2/container/gmap"
  16. "github.com/gogf/gf/v2/internal/intlog"
  17. "github.com/gogf/gf/v2/os/gcmd"
  18. "github.com/gogf/gf/v2/os/gfile"
  19. "github.com/gogf/gf/v2/os/glog"
  20. )
  21. // View object for template engine.
  22. type View struct {
  23. searchPaths *garray.StrArray // Searching array for path, NOT concurrent-safe for performance purpose.
  24. data map[string]interface{} // Global template variables.
  25. funcMap map[string]interface{} // Global template function map.
  26. fileCacheMap *gmap.StrAnyMap // File cache map.
  27. config Config // Extra configuration for the view.
  28. }
  29. type (
  30. Params = map[string]interface{} // Params is type for template params.
  31. FuncMap = map[string]interface{} // FuncMap is type for custom template functions.
  32. )
  33. const (
  34. commandEnvKeyForPath = "gf.gview.path"
  35. )
  36. var (
  37. // Default view object.
  38. defaultViewObj *View
  39. )
  40. // checkAndInitDefaultView checks and initializes the default view object.
  41. // The default view object will be initialized just once.
  42. func checkAndInitDefaultView() {
  43. if defaultViewObj == nil {
  44. defaultViewObj = New()
  45. }
  46. }
  47. // ParseContent parses the template content directly using the default view object
  48. // and returns the parsed content.
  49. func ParseContent(ctx context.Context, content string, params ...Params) (string, error) {
  50. checkAndInitDefaultView()
  51. return defaultViewObj.ParseContent(ctx, content, params...)
  52. }
  53. // New returns a new view object.
  54. // The parameter `path` specifies the template directory path to load template files.
  55. func New(path ...string) *View {
  56. var (
  57. ctx = context.TODO()
  58. )
  59. view := &View{
  60. searchPaths: garray.NewStrArray(),
  61. data: make(map[string]interface{}),
  62. funcMap: make(map[string]interface{}),
  63. fileCacheMap: gmap.NewStrAnyMap(true),
  64. config: DefaultConfig(),
  65. }
  66. if len(path) > 0 && len(path[0]) > 0 {
  67. if err := view.SetPath(path[0]); err != nil {
  68. intlog.Errorf(context.TODO(), `%+v`, err)
  69. }
  70. } else {
  71. // Customized dir path from env/cmd.
  72. if envPath := gcmd.GetOptWithEnv(commandEnvKeyForPath).String(); envPath != "" {
  73. if gfile.Exists(envPath) {
  74. if err := view.SetPath(envPath); err != nil {
  75. intlog.Errorf(context.TODO(), `%+v`, err)
  76. }
  77. } else {
  78. if errorPrint() {
  79. glog.Errorf(ctx, "Template directory path does not exist: %s", envPath)
  80. }
  81. }
  82. } else {
  83. // Dir path of working dir.
  84. if err := view.SetPath(gfile.Pwd()); err != nil {
  85. intlog.Errorf(context.TODO(), `%+v`, err)
  86. }
  87. // Dir path of binary.
  88. if selfPath := gfile.SelfDir(); selfPath != "" && gfile.Exists(selfPath) {
  89. if err := view.AddPath(selfPath); err != nil {
  90. intlog.Errorf(context.TODO(), `%+v`, err)
  91. }
  92. }
  93. // Dir path of main package.
  94. if mainPath := gfile.MainPkgPath(); mainPath != "" && gfile.Exists(mainPath) {
  95. if err := view.AddPath(mainPath); err != nil {
  96. intlog.Errorf(context.TODO(), `%+v`, err)
  97. }
  98. }
  99. }
  100. }
  101. view.SetDelimiters("{{", "}}")
  102. // default build-in variables.
  103. view.data["GF"] = map[string]interface{}{
  104. "version": gf.VERSION,
  105. }
  106. // default build-in functions.
  107. view.BindFuncMap(FuncMap{
  108. "eq": view.buildInFuncEq,
  109. "ne": view.buildInFuncNe,
  110. "lt": view.buildInFuncLt,
  111. "le": view.buildInFuncLe,
  112. "gt": view.buildInFuncGt,
  113. "ge": view.buildInFuncGe,
  114. "text": view.buildInFuncText,
  115. "html": view.buildInFuncHtmlEncode,
  116. "htmlencode": view.buildInFuncHtmlEncode,
  117. "htmldecode": view.buildInFuncHtmlDecode,
  118. "encode": view.buildInFuncHtmlEncode,
  119. "decode": view.buildInFuncHtmlDecode,
  120. "url": view.buildInFuncUrlEncode,
  121. "urlencode": view.buildInFuncUrlEncode,
  122. "urldecode": view.buildInFuncUrlDecode,
  123. "date": view.buildInFuncDate,
  124. "substr": view.buildInFuncSubStr,
  125. "strlimit": view.buildInFuncStrLimit,
  126. "concat": view.buildInFuncConcat,
  127. "replace": view.buildInFuncReplace,
  128. "compare": view.buildInFuncCompare,
  129. "hidestr": view.buildInFuncHideStr,
  130. "highlight": view.buildInFuncHighlight,
  131. "toupper": view.buildInFuncToUpper,
  132. "tolower": view.buildInFuncToLower,
  133. "nl2br": view.buildInFuncNl2Br,
  134. "include": view.buildInFuncInclude,
  135. "dump": view.buildInFuncDump,
  136. "map": view.buildInFuncMap,
  137. "maps": view.buildInFuncMaps,
  138. "json": view.buildInFuncJson,
  139. "xml": view.buildInFuncXml,
  140. "ini": view.buildInFuncIni,
  141. "yaml": view.buildInFuncYaml,
  142. "yamli": view.buildInFuncYamlIndent,
  143. "toml": view.buildInFuncToml,
  144. "plus": view.buildInFuncPlus,
  145. "minus": view.buildInFuncMinus,
  146. "times": view.buildInFuncTimes,
  147. "divide": view.buildInFuncDivide,
  148. })
  149. return view
  150. }