Servage Magazine

Information about YOUR hosting company – where we give you a clear picture of what we think and do!

Live-extensions for better-DOM – Part 2

Monday, April 14th, 2014 by Servage

page_dom_script

DOM.EXTEND

DOM.extend declares a live extension. It accepts a CSS selector as the first argument which defines what elements you want to capture. General advice: try to make the selector simple.

Ideally, you should only use a tag name, class or attribute with or without a value or their combinations with each other. These selectors can be tested quicker without calling an expensive matchesSelector method.

The second argument is a live extension definition. All properties of the object will be mixed with an element wrapper interface except constructor and event handlers.

Let’s look at a simple example. Let’s assume we have such an element on a Web page:

<div>…</div>

The task is to show it as a modal dialog. This is how the live extension could look like:

DOM.extend(".modal-dlg", {
  constructor: function() {
    var backdrop = DOM.create("div.modal-dlg-backdrop");
    // using bind to store reference to backdrop internally

this.showModal = this.showModal.bind(this, backdrop);

// we will define event handlers later

  },
  showModal: function(backdrop) {
    this.show();
    backdrop.show();
  }

});

Now you can access the public method showModal in any (present or future) element that has the modal-dlg class (in our case this is the signin-form div):

var signinForm = DOM.find(“.signin-form”);

 

DOM.find(“.signin-btn”).on(“click”, function() {

// the signin button doesn’t have the modal-dlg class

// so it’s interface doesn’t contain the showModal method

console.log(this.showModal); // => undefined

signinForm.showModal(); // => shows the signin dialog

});

Note: The better-dom-legacy.js file which is included conditionally for Internet Explorer versions 8 and 9, contains the es5-shim library so you can safely use standards-based EcmaScript 5 functions (such as Function.prototype.bind) in your code. I’ve been using the bind method heavily in my code to build testable methods easily.

THE CONSTRUCTOR PROPERTY

The constructor function is called when an element becomes visible. This is because of the animationstart event that is used to implement DOM.extend. Browsers are clever so they don’t fire animation events for hidden elements. This lazy initialization saves resources sometimes, but be careful with accessing initially hidden elements.

In older Internet Explorers versions such as 8 and 9, contentready event from better-dom-legacy.htc is used to implement live extensions. Therefore, the constructor function executes immediately in these browsers — even for hidden elements.

Note: Keep in mind not to rely on time whenever an extension has been initialized. The actual initialization of a live extension varies across browsers!

Constructor is usually the place where you attach event handlers and perform DOM mutations where necessary. Once the function has been completed, all methods that begin with “on” (in better-dom 1.7 also “do”) followed by an uppercase letter, event handlers, will be removed from the element wrapper’s interface.

Let’s update our .signin-form live extension with the help of a close button and the ESC key:

DOM.extend(“.modal-dlg”, {

constructor: function() {

var backdrop = DOM.create(“div.modal-dlg-backdrop”),

closeBtn = this.find(“.close-btn”);

 

    this.showModal = this.showModal.bind(this, backdrop);
    // handle click on the close button and ESC key
    closeBtn.on("click", this.onClose.bind(this, backdrop));
    DOM.on("keydown", this.onKeyDown.bind(this, closeBtn), ["which"])
  },
  showModal: function(backdrop) {
    this.show();
    backdrop.show();
  },
  onClose: function(backdrop) {
    this.hide();
    frame.hide();
  },
  onKeyDown: function(closeBtn, which) {
    if (which === 27) {
      // close dialog by triggering click event
      closeBtn.fire("click");
    }
  }
});

Despite the fact that the live extension contains both onClose and onKeyDown methods, they won’t be mixed into the element wrapper interface:

var signinForm = DOM.find(“.signin-form”);

 

console.log(signinForm.onClose); // => undefined

console.log(signinForm.onKeyDown); // => undefined

This kind of behavior exists simply because you can have multiple live extensions for a single element that may overload public methods of each other and produce unexpected results. For event handlers, this is not possible; they exist only inside of the constructor function.

EXTENDING * ELEMENTS

Sometimes it is useful to extend all of the element wrappers with a particular method (or methods). But then again, you can also use the universal selector to solve the problem:

DOM.extend("*", {
  gesture: function(type, handler) {
    // implement gestures support
  }
});

DOM.find("body").gesture("swipe", function() {
  // handle a swipe gesture on body
});

 

Live-extensions for better-DOM - Part 2, 3.5 out of 5 based on 4 ratings
You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

No comments yet (leave a comment)

You are welcome to initiate a conversation about this blog entry.

Leave a comment

You must be logged in to post a comment.