@@ -60,7 +60,53 @@ export class TemplateHelper {
6060 }
6161 }
6262
63- private static _expression = / { { + \s * [ $ \w \. ( ) \[ \] ] + \s * } } + / g;
63+ /**
64+ * Set an alternative binding syntax. Default is {{ <value> }}
65+ *
66+ * @static
67+ * @param {string } startStr start of binding syntax
68+ * @param {string } endStr end of binding syntax
69+ * @memberof TemplateHelper
70+ */
71+ public static setBindingSyntax ( startStr : string , endStr : string ) {
72+ this . _startExpression = startStr ;
73+ this . _endExpression = endStr ;
74+
75+ const start = this . escapeRegex ( this . _startExpression ) ;
76+ const end = this . escapeRegex ( this . _endExpression ) ;
77+
78+ this . _expression = new RegExp ( `${ start } \\s*\([$\\w\\.()\\[\\]]+\)\\s*${ end } ` , 'g' ) ;
79+ }
80+
81+ /**
82+ * Global context containing data or functions available to
83+ * all templates for binding
84+ *
85+ * @readonly
86+ * @static
87+ * @memberof TemplateHelper
88+ */
89+ public static get globalContext ( ) {
90+ return this . _globalContext ;
91+ }
92+
93+ private static _globalContext = { } ;
94+
95+ private static get expression ( ) {
96+ if ( ! this . _expression ) {
97+ this . setBindingSyntax ( '{{' , '}}' ) ;
98+ }
99+
100+ return this . _expression ;
101+ }
102+
103+ private static _startExpression : string ;
104+ private static _endExpression : string ;
105+ private static _expression : RegExp ;
106+
107+ private static escapeRegex ( string ) {
108+ return string . replace ( / [ - \/ \\ ^ $ * + ? . ( ) | [ \] { } ] / g, '\\$&' ) ;
109+ }
64110
65111 // simple implementation of deep cloneNode
66112 // required for nested templates in polyfilled browsers
@@ -83,8 +129,8 @@ export class TemplateHelper {
83129 }
84130
85131 private static expandExpressionsAsString ( str : string , context : object , additionalContext : object ) {
86- return str . replace ( this . _expression , match => {
87- const value = this . evalInContext ( this . trimExpression ( match ) , { ...context , ...additionalContext } ) ;
132+ return str . replace ( this . expression , ( match , p1 ) => {
133+ const value = this . evalInContext ( p1 || this . trimExpression ( match ) , { ...context , ...additionalContext } ) ;
88134 if ( value ) {
89135 if ( typeof value === 'object' ) {
90136 return JSON . stringify ( value ) ;
@@ -238,10 +284,12 @@ export class TemplateHelper {
238284 }
239285
240286 private static evalBoolInContext ( expression , context ) {
287+ context = { ...context , ...this . globalContext } ;
241288 return new Function ( 'with(this) { return !!(' + expression + ')}' ) . call ( context ) ;
242289 }
243290
244291 private static evalInContext ( expression , context ) {
292+ context = { ...context , ...this . globalContext } ;
245293 const func = new Function ( 'with(this) { return ' + expression + ';}' ) ;
246294 let result ;
247295 try {
@@ -252,17 +300,16 @@ export class TemplateHelper {
252300 }
253301
254302 private static trimExpression ( expression : string ) {
255- let start = 0 ;
256- let end = expression . length - 1 ;
257-
258- while ( expression [ start ] === '{' && start < end ) {
259- start ++ ;
260- }
261-
262- while ( expression [ end ] === '}' && start <= end ) {
263- end -- ;
303+ expression = expression . trim ( ) ;
304+
305+ if ( expression . startsWith ( this . _startExpression ) && expression . endsWith ( this . _endExpression ) ) {
306+ expression = expression . substr (
307+ this . _startExpression . length ,
308+ expression . length - this . _startExpression . length - this . _endExpression . length
309+ ) ;
310+ expression = expression . trim ( ) ;
264311 }
265312
266- return expression . substring ( start , end + 1 ) . trim ( ) ;
313+ return expression ;
267314 }
268315}
0 commit comments