diff options
| author | pabs@pablotron.org <pabs@pablotron.org> | 2014-08-24 01:15:02 -0400 | 
|---|---|---|
| committer | pabs@pablotron.org <pabs@pablotron.org> | 2014-08-24 01:15:02 -0400 | 
| commit | dd9d9521f810a038a68134756647c10d05815a26 (patch) | |
| tree | 531b2a41f522a23f3bc3f5f716a0027a54d91818 | |
| download | luigi-template-dd9d9521f810a038a68134756647c10d05815a26.tar.xz luigi-template-dd9d9521f810a038a68134756647c10d05815a26.zip | |
initial commit (moved from different repo)
| -rw-r--r-- | luigi-template.js | 196 | ||||
| -rw-r--r-- | test.js | 58 | 
2 files changed, 254 insertions, 0 deletions
| diff --git a/luigi-template.js b/luigi-template.js new file mode 100644 index 0000000..8bf35ef --- /dev/null +++ b/luigi-template.js @@ -0,0 +1,196 @@ +LuigiTemplate = (function() { +  "use strict"; + +  var VERSION = '0.3.0'; + +  // list of built-in filters +  var FILTERS = { +    hash: function(v, args) { +      return 'hash(' + v + ')'; +    }, + +    uc: function(v) { +      return v.toUpperCase(); +    }, + +    lc: function(v) { +      return v.toLowerCase(); +    }, + +    pluralize: function(v) { +      return v + 's'; +    }, + +    length: function(v) { +      return v.length; +    }, + +    trim: function(v) { +      return (v || '').replace(/^\s+|\s+$/mg, ''); +    }, + +    h: (function() { +      var LUT = { +        '"': '"', +        "'": ''', +        '>': '>', +        '<': '<', +        '&': '&' +      }; +       +      return function(v) { +        if (v === undefined || v === null) +          return ''; + +        return (v || '').replace(/(['"<>&])/g, function(s) { +          return LUT[s]; +        }); +      }; +    })() +  }; + +  var RES = { +    run:    /%\{\s*(\w+)((\s*\|\s*\w+\s*(\([\w\s,-]+\))?)*)\}/g, +    filter: /(\w+)\s*(\(([\w\s,-]+)\))?/, +    trim:   /^\s+|\s+$/ +  }; + +  function init(s, o) { +    this.s = s; +    this.o = o; +    this.filters = (o && 'filters' in o) ? o.filters : {}; +  }; + +  function safe_trim(s) { +    return ((s !== undefined) ? s : '').replace(RES.trim, ''); +  } + +  // given a filter string, return a list of filters +  function make_filter_list(s) { +    var i, l, a, md, r = [], fs = s.split(/\s*\|\s*/); + +    if (s.length > 0 && fs.length > 0) { +      for (i = 1, l = fs.length; i < l; i++) { +        if (md = fs[i].match(RES.filter)) { +          r.push({ +            k: md[1], +            a: safe_trim(md[3]).split(/\s*,\s*/) +          }); +        } else { +          throw new Error("invalid filter string: " + fs[i]); +        } +      } +    } + +    return r; +  } + +  function get_filter(k, me) { +    var r = me.filters[k] || FILTERS[k]; + +    if (!r) +      throw new Error("unknown filter: " + k); + +    return r; +  } + +  function run(o) { +    var i, l, f, fs, me = this; + +    // TODO: add compiled support here + +    return this.s.replace(RES.run, function(m, k, filters) { +      var r = o[k]; + +      // build filter list +      fs = make_filter_list(filters); + +      // iterate over and apply each filter +      for (i = 0, l = fs.length; i < l; i++) { +        // get/check filter +        f = get_filter(fs[i].k, me); + +        // apply filter +        r = f(r, fs[i].a, o, this); +      } + +      // return result +      return r; +    }); +  } + +  function get_inline_template(key) { +    // get script element +    var e = document.getElementById(key); +    if (!e) +      throw new Error('unknown inline template key: ' + key); + +    // return result +    return e.innerText || ''; +  } + +  // declare constructor +  var T = init; + +  // declare run method +  T.prototype.run = run; + +  // declare cache constructor +  T.Cache = function(templates, try_dom) { +    this.templates = templates; +    this.try_dom = !!try_dom; +    this.cache = {}; +  }; + +  // cache run method +  T.Cache.prototype.run = function(key, args) { +    if (!(key in this.cache)) { +      var s = null; + +      if (key in this.templates) { +        // get template from constructor templates +        s = this.templates[key].join(''); +      } else if (this.try_dom) { +        // get source from inline script tag +        s = get_inline_template(key); +      } else { +        throw new Error('unknown key: ' + key); +      } + +      // cache template +      this.cache[key] = new T(s); +    } + +    // run template +    return this.cache[key].run(args); +  }; + +  // declare domcache constructor +  T.DOMCache = function() { +    this.cache = {}; +  }; +   +  // domcache run method +  T.DOMCache.prototype.run = function(key, args) { +    if (!(key in this.cache)) +      this.cache[key] = new T(get_inline_template(key)); + +    // run template +    return this.cache[key].run(args); +  }; + +  // create DOMCache singleton +  T.dom = new T.DOMCache(); + +  // expose filters and version +  T.FILTERS = FILTERS; +  T.VERSION = VERSION; + +  // add singleton run +  T.run = function(s, o) { +    return new T(s).run(o); +  } + +  // expose interface +  return T; +}()); @@ -0,0 +1,58 @@ + +load('luigi-template.js'); + +// define custom template filter +function custom_filter(v) { +  return "foo" + v + "bar"; +} + +function custom_filter_with_args(v, args) { +  var i, l, r = [v]; + +  for (i = 0, l = args.length; i < l; i++) +    r.push(args[i]); + +  return r.join(' and '); +} + +// add custom template filters +LuigiTemplate.FILTERS.custom = custom_filter; +LuigiTemplate.FILTERS.custom_args = custom_filter_with_args; + +// build template string +var template_str = [ +  // test basic templates +  "%{greet}, %{name}!", + +  // test filters and filters with parameters +  "Your name hashes to: %{name|hash(sha1)|uc}", + +  // test custom filter +  "Your custom filtered name is: %{name|custom}", + +  // test custom filter with arguments +  "Your custom_args name is: %{name|custom_args(foo,bar,baz)}", + +  // test whitespace in filters +  "random test: %{name | hash( sha512 ) | uc }", + +  // test pluralize filter +  'pluralize test (0): %{count_0} %{count_0 | pluralize(item)}', +  'pluralize test (1): %{count_1} %{count_1 | pluralize(item)}', +  'pluralize test (10): %{count_10} %{count_10 | pluralize(item)}', + +  // terminating newline +  '' +].join("\n"); + +// build template +var t = new LuigiTemplate(template_str); + +// print results +print(t.run({ +  greet:    'hello', +  name:     'paul', +  count_0:  0, +  count_1:  1, +  count_10: 10 +})); | 
