Draccoz
5/17/2016 - 10:53 PM

Google Polymer behavior allowing to use simple javascript expressions inside of the templates

Google Polymer behavior allowing to use simple javascript expressions inside of the templates

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/webcomponentsjs/0.7.22/webcomponents-lite.min.js"></script>
  <script>
    //    window.Polymer = {dom: 'shadow'};
  </script>
  <link href="http://polygit.org/polymer+:master/components/polymer/polymer.html" rel="import">
  <script src="polymer-expression-binding-behavior.js"></script>
  <dom-module id="test-module">
    <template>
      <p>Born in {{birthYear}} currently are {{{currentYear - birthYear}}} years old</p>
    </template>
  </dom-module>
</head>
<body>
<script>
  window.addEventListener('HTMLImportsLoaded', function () {
    var currentYear = new Date().getFullYear();

    Polymer({
      is: "test-module",
      behaviors: [new Polymer.expressBindingBehavior("test-module")],
      properties: {
        currentYear: {
          type: Number,
          value: currentYear
        },
        birthYear: Number
      }
    });


    function testBinding(year) {
      var node = document.createElement("test-module");
      node.birthYear = year;
      var actual = Polymer.dom(node.root).textContent.trim();
      var expected = "Born in " + year + " currently are " + (currentYear - year) + " years old";
      document.writeln("Test <strong>" + (actual === expected ? "passed" : "failed") + "</strong> for `birthYear` equal to " + year + "<br>");
    }

    testBinding(1989);
    testBinding(1969);
    testBinding(1995);
  });
</script>
</body>
</html>
(function (global) {
  var dynamicFunctionsNames = {};
  var cached = {};

  function expressBinding(match, p) {
    var fun;
    var attrs = p
      .replace(/&amp;/g, "&") // decode &
      .replace(/&lt;/g, "<")  // decode <
      .replace(/&gt;/g, ">")  // decode >
      .replace(/&quot;/g, "\"") // decode "
      .replace(/&apos;/g, "'") // decode '
      .replace(/'[^']+'/, "") // remove single quote strings
      .replace(/"[^"]+"/, "") // remove double quote strings
      .match(/([a-z_$\.][\w_$]*)/ig)  // get all words starting from a letter, _, $ or a dot
      .filter(function (el) {
        return el[0] !== "."
      });  // now exclude the words starting with a dot

    if (!(fun = cached[p])) {
      fun = cached[p] = new (Function.prototype.bind.apply(Function, [null].concat(attrs).concat("return " + p)));
    }

    var camelCasedName = this.is.replace(/\-([\w])/g, function (match, p) {
      return p.toUpperCase()
    });

    var dynamicFunctionNameIndex = ++dynamicFunctionsNames[camelCasedName];
    if (!dynamicFunctionNameIndex) {
      dynamicFunctionNameIndex = dynamicFunctionsNames[camelCasedName] = 1;
    }

    var functionName = camelCasedName + "_" + dynamicFunctionNameIndex;
    this.prototype[functionName] = fun;
    return "[[" + functionName + "(" + attrs.join(",") + ")]]";
  }

  function expressBindingBehavior(id) {
    var module = Polymer.DomModule.import(id);
    var template = module.querySelector("template");

    template.innerHTML = template.innerHTML.replace(/\{\{\{(.*)}}}/g, expressBinding.bind({
      is: id,
      prototype: this
    }))
  }

  if (global.Polymer) {
    global.Polymer.expressBindingBehavior = expressBindingBehavior;
  } else {
    global.addEventListener('HTMLImportsLoaded', function () {
      global.Polymer.expressBindingBehavior = expressBindingBehavior;
    });
  }
}(this));