Moon vs. Metamorph (v12)

Revision 12 of this benchmark created by mekwall on


Description

Testing a prototype of a less compatible, but more powerful way of updating content.

Why add placeholders to the DOM when we can just keep references?

Preparation HTML

<div id="container"></div>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script src="https://raw.github.com/gist/2b338ff59972a1c42601/04d740ea357d623aefe7a4130aeca98618dc0cd1/metamorph.comments.js">
</script>
<script>
MetamorphWithComments = Metamorph;
</script>
<script src="https://raw.github.com/tomhuda/metamorph.js/master/lib/metamorph.js">
</script>
<script>
MetamorphOrg = Metamorph;
(function(window, $, undefined){
    if (!window.Moon) window.Moon = {};
    var pl = $("<div>");
    View = function (name, template) {
        var self = this;
        self.name = name;
        self.template = $(template);
        self._refs = {};
        var vars = self.template[0].nodeName == "MOON" ? 
          self.template : self.template.find("moon");
        vars.each(function(){
          var $this = $(this);
          var name = $this.data("var");
          var editable = $this.data("editable") ? true : false;
          var contents = $this.contents();
          var obj = $({
              name: name,
              initial: $this.clone().contents(),
              editable: editable,
              modifier: $this.data("modifier"),
              ref: contents,
              val: contents.html()
          });
            
          obj.toString = function() {
              return this[0].ref.html();
          };
            
          if (editable) {
              var span = $('<span contenteditable="true"></span>').on("keyup", function(){
                  obj.trigger("update", [$(this).html(), true]);
              });
              obj[0].ref.wrap(span);
          }
           
          obj.on("update", function(e, val, noupdate) {
              if (!noupdate) {
                  if (val === "") { val = this.initial.clone(); }
                  if (this.modifier) {
                      val = View.Modifier[this.modifier](val);
                  }
                  pl.html(val);
                  var contents = pl.contents();
                  if (contents) {
                      this.ref.replaceWith(contents);
                      this.ref = contents;
                  }
              }
          });
          
          self._refs[name] = obj;
                        
          $this.replaceWith(contents);

          Object.defineProperty(self, name, {
              get: function() {
                  return self._refs[name];
              },
              set: function(val) {
                  self._refs[name].trigger("update", [val]);
              }
          });
        });

        return this;
    }
        
    $.extend(View.prototype, {
        update: function(values) {
            for (key in values) {
                self._refs[name].trigger("update", values[key]);         
            }
        },
        appendTo: function(selector) {
            $(selector).append(this.template);
        }            
    });

    View.Modifier = {
        date: function(val) {
            var date = new Date(val);
            return date.getUTCDate() + "/" + (date.getUTCMonth()+1);
        },
        ucwords: function(val) {
            if (typeof val !== "object") {
                val = val.split(" ").map(function(o,i){
                    var letters = o.split("");
                    return letters[0].toUpperCase() + letters.slice(1).join("");
                }).join(" ");
            }
            return val;
        }
    };

    window.Metamorph = (function() {
        var guid = 0;
        var Metamorph = function(html) {
            var name = "metamorph-"+(guid++);
            html = '<moon data-var="'+name+'">'+html+'</moon>';
            var view = new View(name, html);
            
            view.outerHTML = function() {
                return this._refs[name][0].ref;
            }
                
            view.html = function(html) {
                this[name].trigger("update", html);
                return this._refs[name][0].ref;
            }
            
            view.remove = function() {}
            
            return view;
        }
            
        Metamorph.prototype

        return Metamorph;
    }());

    window.Moon.View = View;

}(window, window.jQuery));

var container = $("#container");
</script>

Teardown


    container.empty();
  

Test runner

Ready to run.

Testing in
TestOps/sec
metamorph (script placeholder)
var morph1 = MetamorphOrg("one two three");
container.append(morph1.outerHTML());
morph1.html("three four five six");
ready
metamorph (comment placeholder)
var morph2 = MetamorphWithComments("one two three");
container.append(morph2.outerHTML());
morph2.html("three four five six");
ready
moon (wrapper)
var morph3 = Metamorph("one two three");
container.append(morph3.outerHTML());
morph3.html("three four five six");
ready
moon
var view = new Moon.View("foo", "<div><moon data-var='foo'>one two three</moon></div>");
view.appendTo(container);
view.foo = "three four five six";
ready

Revisions

You can edit these tests or add more tests to this page by appending /edit to the URL.