• essential.js

  • ¶
    EssentialJS v0.5.0
    Copyright (c)2014 Roberto Dip
    Distributed under MIT license
    http://roperzh.github.io/essential.js
    
    window.Essential = {
    
      rootElement: document,
    
      Core: {},
  • ¶

    Start

  • ¶

    since v0.1.0

    A wrapper of #Essential.loadBehaviors, this method is deprecated direct usage of loadBehaviors is encouraged.

    Param application[Object] an object containing behaviors names as a key and behaviors objects as a value.

      start: function(application) {
        this.loadBehaviors({
          application: application
        });
      },
  • ¶

    Load Behaviors

  • ¶

    since v0.5.0

    Wakes up the engine, searching and attaching behaviors with their proper elements

    Param options[Object] allows the follwing values:

    • application[Object] an object containing behaviors names as a key and behaviors objects as a value
    • context [DOMElement] context to look for behaviors. If no context is provided the default is Essential.rootElement

    Example

    MyApp = {};
    MyApp.Carousel = Essential.Behaviors.extend();
    Essential.loadBehaviors({ application: MyApp, context: document });
    // will attach the carousel behavior to proper elements
    
      loadBehaviors: function(options) {
        options.context = options.context || this.rootElement;
    
        var initializedBehaviors =
          this.initializeBehaviors(options.application, options.context);
    
        this.launchBehaviors(initializedBehaviors);
      },
  • ¶

    Initialize Behaviors

  • ¶

    Crawls an element looking for behaviors and call #new on every behavior found with lateStart = true, so the behaviors are initialized, but there is no event delegation

    param application [Object] object containing behaviors to be initialized

    param element [DomeElement] context to look for declared behaviors

      initializeBehaviors: function(application, element) {
        var behaviorsInDOM = this.Core.crawl(element),
          rawBehaviorsNames = Object.keys(behaviorsInDOM),
          initializedBehaviors = [],
          i = -1;
    
        while(rawBehaviorsNames[++i]) {
          var rawName = rawBehaviorsNames[i],
            name = this.Core.camelize(rawName),
            behavior = application[name];
    
          if(typeof behavior !== "undefined") {
            var elementsWithBehavior = behaviorsInDOM[rawName],
              j = -1;
    
            while(elementsWithBehavior[++j]) {
              var initializedBehavior = behavior.new(elementsWithBehavior[j], true);
              initializedBehaviors.push(initializedBehavior);
            }
          }
        }
    
        return initializedBehaviors;
      },
  • ¶

    Launch Behaviors

  • ¶

    Given a list of behaviors, this method sort these based on their priority value, and then call #start on every one

    param behaviorList[Array<Object>] an array containing behaviors already initialized

      launchBehaviors: function(behaviorList) {
        var sortedBehaviors = behaviorList.sort(this.Core.SortMethods.byPriority),
          i = -1;
    
        while(sortedBehaviors[++i]) {
          sortedBehaviors[i].start();
        }
      }
    };
  • ¶

    Behavior

  • ¶

    Represents a behavior of some element or group of elements. The objetive is define a set of rules and events which can be associated to an element and reutilized later on

    When a behavior is defined, a hash of events must be defined too, and on initialization a DOM element must be provided

    Also you can define an init function, which is always called when the behavior is initialized

    Example

    Carousel = Essential.Behavior.extend({
      events: {
        "click .next": "goToNextSlide"
      },
    
     init: function() {
       // Called on behavior initialization
     },
    
      goToNextSlide: function(e) {
        //...
      }
    });
    
    var carousel = Carousel.new(domElement);
    
    Essential.Behavior = Proto.extend({
      constructor: function(domElement, lateStart) {
        this.el = domElement;
  • ¶

    A behavior can be initialized without attaching events with the lateStart flag, if it is present the methods delegateEvents and ìnit are omitted but can be called later with start

    Example

    carousel = new Carousel(domElement, true);
    // delegateEvents and init not called
    
    carousel.start();
    // delegateEvents and init called
    
        if(!lateStart) {
          this.start();
        }
      },
    
      start: function() {
        this.delegateEvents();
        this.listenChannels();
    
        if(typeof this.init === "function") {
          this.init();
        }
      },
  • ¶

    Delegate Events

  • ¶

    since v0.1.0

    Delegates events declared in this.events, using this.el as a context

      delegateEvents: function() {
        Essential.Core.mapEvents.call(this, this.events, this.el);
      },
  • ¶

    Listen Channels

  • ¶

    since v0.5.0

    Attach event handlers to channels declared in this.channels usingdocument` as a context

      listenChannels: function() {
        Essential.Core.mapEvents.call(this, this.channels, document);
      },
  • ¶

    Emit

  • ¶

    Facilitates the emission of custom events through the CustomEvent Interface. IE9 and IE10 are supported via polyfill

    since v0.5.0

    param dataset[Object] valid dataset values are:

    • channel: [String] name (identifier) of the channel

    • context: [DOMElement] DOM context in which the event is triggered, this parameter can be ommited. Default value is document

    • bubles: [Boolean] defines if this event should bubble or not, defaults to true

    • cancelable: [Boolean] indecates whether the event is cancelable, defaults to false

    • data: [Object] data to be included in the "detail" key of the event can be accesed later via event.detail (check the CustomEvent spec for more info)

      emit: function(dataset) {
        dataset.context = dataset.context || this.el;
        dataset.data = dataset.data || {};
        dataset.bubbles = dataset.bubbles || true;
        dataset.cancelable = dataset.cancelable || false;
    
        var customEvent = new CustomEvent(dataset.channel, {
          "bubbles": dataset.bubbles,
          "cancelable": dataset.cancelable,
          "detail": dataset.data
        });
    
        dataset.context.dispatchEvent(customEvent);
      },
    
      priority: 0
    });
  • ¶

    Map Events

  • ¶

    since v0.5.0

    Given a document context, maps a hash of events to all ocurrences in the context using the DOM Event Interface

    param events[Object] key-value map which follows some conventions:

    • key: must be a String, containing the event name. Optionally after the event name a valid CSS selector must be placed, for example "click #element"

    • value: must be a name of a funciton pertaining to the current in which mapEvents its executed

    param context[DOMElement] element to search through

    Example

    var events = {
      "click .next": "goToNextSlide"
    };
    
    Essential.Core.mapEvents(events, document);
    
    Essential.Core.mapEvents = function(events, context) {
      if(typeof events === "undefined") {
        return;
      }
    
      var delegateEventSplitter = /^(\S+)\s*(.*)$/;
    
      for(var key in events) {
        var method = events[key];
    
        var match = key.match(delegateEventSplitter);
        var eventName = match[1],
          selector = match[2],
          nodeList = selector ? context.querySelectorAll(selector) : [context];
    
        if(typeof this[method] === "undefined") {
          continue;
        }
    
        Essential.Core.bind(eventName, nodeList, this[method].bind(this));
      }
    };
  • ¶

    Bind

  • ¶

    Binds an event to a node

    Param eventName[String] name of the event to be binded

    Param callback[Function] function to be called when the event is triggered

    Param nodeList[NodeList, Array] node elements to be binded

    Example

    var nodeList = document.querySelectorAll("*");
    
    Essential.Core.bind("hover", nodeList, function() {
      alert("hover!");
    });
    
    // If the hover event is triggered for any of the
    // elements in the nodeList the alert will appear
    
    Essential.Core.bind = function(eventName, nodeList, callback) {
      var i = -1;
    
      while(nodeList[++i]) {
        var currentElement = nodeList[i];
    
        if(currentElement.addEventListener) {
          nodeList[i].addEventListener(eventName, callback);
        } else {
          currentElement.attachEvent("on" + eventName, callback);
        }
      }
    };
  • ¶

    RegExp Helpers

  • ¶
  • ¶

    Looks for some of this characters : - _ the objetive is allow to define behaviors like cool:carousel or small-carousel

    Essential.Core.SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g;
  • ¶

    Finds the first letter of a given string

    Essential.Core.FIRST_LETTER_REGEXP = /^[a-z]/g;
  • ¶

    Camelize

  • ¶

    Converts strings to UpperCamelCase

    Param name[String] the name to be camelized

    Returns String camel case representation of the name

    Example

    Essential.Core.camelize("cool-carousel");
    
    // => CoolCarousel
    
    Essential.Core.camelize = function(name) {
      return name.
      replace(Essential.Core.FIRST_LETTER_REGEXP, function(letter) {
        return letter.toUpperCase();
      }).
      replace(Essential.Core.SPECIAL_CHARS_REGEXP, function(_, separator, letter) {
        return letter.toUpperCase();
      });
    };
  • ¶

    Crawl

  • ¶

    Scans the DOM looking for behaviors

    Return Array<Object> an array of objects with the behavior name as a key and an array of DOM nodes as a value

    Example

    <div behavior="carousel"></div>
    
    Essential.Core.crawl();
    
    // => [{ carousel: [<HTMLDivElement>, <HTMLDivElement>] }]
    
    Essential.Core.crawl = function(rootElement) {
      var all = rootElement.querySelectorAll("[data-behavior], [behavior]"),
        i = -1,
        result = {};
    
      while(all[++i]) {
        var currentElement = all[i],
          rawBehaviors = currentElement.getAttribute("data-behavior") || currentElement.getAttribute("behavior"),
          behaviorsList = rawBehaviors.split(" "),
          j = -1;
    
        while(behaviorsList[++j]) {
          var currentBehavior = behaviorsList[j];
    
          if(result[currentBehavior]) {
            result[currentBehavior].push(currentElement);
          } else {
            result[currentBehavior] = [currentElement];
          }
        }
      }
    
      return result;
    };
  • ¶

    Sort Methods

  • ¶

    Namespace to hold sort methods

    Essential.Core.SortMethods = {
  • ¶

    By Priority

  • ¶

    This criteria allows to sort behaviors based on their respective priorities, in descending order, that means behaviors with bigger priority will appear first

      byPriority: function(behaviorA, behaviorB) {
        return behaviorB.priority - behaviorA.priority;
      }
    };