npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

hap

v2.1.1

Published

An extension to the Node.js events.EventEmitter.

Downloads

20

Readme

hap

Greenkeeper badge

Introduction

An extension to the Node.js events.EventEmitter with an important factor, "bubbling".

hap's EventEmitter inherits all methods from Node.js's events.EventEmitter, but has a new method #fire(). It works the same as #emit() but sets off a chain of events that pass around a facade and bubble up to any #parent EventEmitters.

Let's jump in to an example:

var EventEmitter = require('hap').EventEmitter,
    util         = require('util'),
    emitter;

function MyTestEmitter(){
  EventEmitter.apply(this, arguments);
}

util.inherits(MyTestEmitter, EventEmitter);

emitter = new MyTestEmitter();

emitter.on('test event', function(e){
  console.log(e);
});

emitter.fire('test event');

The above example is no different to any normal observer pattern... and the facade would be logged to the console. Now let's see the bubbling in action:

var EventEmitter = require('hap').EventEmitter,
    util         = require('util'),
    emitter, parentEmitter;

function MyTestEmitter(){
  EventEmitter.apply(this, arguments);
}

util.inherits(MyTestEmitter, EventEmitter);

parentEmitter  = new MyTestEmitter();
emitter        = new MyTestEmitter();

emitter.setParent(parentEmitter);

parentEmitter.on('test event', function(e){
  console.log('Parent');
});

emitter.on('test event', function(e){
  console.log('Child');
});

parentEmitter.fire('test event');
// => Child
// => Parent

In the above example the event seems to start at the child object, even though it was called in the parent. That's very similar to what happens in the DOM for example. First, there is a "capture" event that starts at the target element and then fires within each child. Once it hits the bottom, the event then bubbles up to the top.

Here's a quote from quirksmode:

Event capturing

When you use event capturing

                 | |
  ---------------| |-----------------
  | element1     | |                |
  |   -----------| |-----------     |
  |   |element2  \ /          |     |
  |   -------------------------     |
  |        Event CAPTURING          |
  -----------------------------------

the event handler of element1 fires first, the event handler of element2 fires last.

Event bubbling

When you use event bubbling

                 / \
  ---------------| |-----------------
  | element1     | |                |
  |   -----------| |-----------     |
  |   |element2  | |          |     |
  |   -------------------------     |
  |        Event BUBBLING           |
  -----------------------------------

the event handler of element2 fires first, the event handler of element1 fires last.

W3C model

W3C has very sensibly decided to take a middle position in this struggle. Any event taking place in the W3C event model is first captured until it reaches the target element and then bubbles up again.

                   | |  / \
  -----------------| |--| |-----------------
  | element1       | |  | |                |
  |   -------------| |--| |-----------     |
  |   |element2    \ /  | |          |     |
  |   --------------------------------     |
  |        W3C event model                 |
  ------------------------------------------

The hap model

hap uses the "W3C model". First there is a capturing phase of which you can attach to with the #before() method. There the bubbling takes place of which you can listen to with the #on() method. And finally, to add some extra power, the event will bubble from bottom to top one more time of which you can listen to with the #after() method.

                   | |  / \  / \
  -----------------| |--| |--|-|------------
  | parent         | |  | |  | |           |
  |   -------------| |--| |--|-|------     |
  |   |child       \ /  | |  | |     |     |
  |   --------------------------------     |
  |        hap event model                 |
  ------------------------------------------

A real life example

Here's a an example using an Express.js like framework:

// app.js

var express = require('express'),
    hap     = require('hap'),
    http    = require('http'),
    util    = require('util'),
    app     = express(),
    nav     = require('./nav'); // See below

util._extend(app, hap.EventEmitter.prototype);

// This event is fired by express when an express instance is used by another
// express instance.
app.on('mount', function(parent){
  this.setParent(parent);
});

// "nav" is a child app
app.use(nav()); 

// When our app is ready to render the nav, we want to add some items to it.
app.on('nav', function(e){
  e.val().push({
    content : 'Item 1',
    id      : 'nav-item-1'
  });
});

app.get('/', function(req, res){
  res.send(emitter.fire('nav'));
  // => <nav><ul><li id="nav-item-1">Item 1</li></ul></nav>
});

http.createServer(app).listen(8080);
// nav.js

var express = require('express'),
    hap     = require('hap'),
    Html    = require('tag').Html,
    util    = require('util');

module.exports = function(){
  var app = express();

  util._extend(app, hap.EventEmitter.prototype);

  // The nav var needs to be created before (the 
  // capturng phase) the nav is rendered.
  app.before('nav', function(e){
    e.val([]);
  });

  // Add a listener to the end of event process to render the nav.
  app.after('nav', function(e){
    var ul  = Html.factory('ul'),
        nav = Html.factory('nav');

    e.val().forEach(function(item){
      var content = item.content,
          li;

      delete item.content;
      li = Html.factory('li', item, content);
      ul.appendChild(li);
    });
      
    nav.appendChild(ul);
    e.val(nav.toHTML());
  });
};

Installation

npm i hap

API

EventEmitter

#addChild(emitter)

Adds an emitter as a child to this object.

Parameters
  • emitter {hap.EventEmitter} The child emitter

#after(eventName, fn)

Adds a listener to the final bubling stage.

Parameters
  • eventName {String} The event to attach to
  • fn {Function} Callback function

#before(eventName, fn)

Adds a listener to the capturing stage.

Parameters
  • eventName {String} The event to attach to
  • fn {Function} Callback function

#bubble(eventName e)

A protected method used to trigger the bubbling sequence.

Parameters
  • eventName {String} The event to bubble
  • e {hap.EventFacade} The event facade

#capture(eventName e)

A protected method use to trigger the capturing sequence.

Parameters
  • eventName {String} The event to start capturing
  • e {hap.EventFacade} The event facade

#emit(eventName, attrs)

  • see events.EventEmitter

#fire(eventName, attrs)

Similar to the #emit() method but dispatches the capturing/bubbling sequence passing a facade object and return a modified value.

Parameters
  • eventName {String} The event to emit
  • attrs {Object | EventFacade} A hash of attributes or an event facade

#on(eventName, fn)

  • see events.EventEmitter

#once(eventName, fn)

  • see events.EventEmitter

#onceAfter(eventName, fn)

Similar to #once() but attaches the listener to the final bubbling sequence.

Parameters
  • eventName {String} The event to emit
  • fn {Function} The listener callback

#onceBefore(eventName, fn)

Similary to #once() but attached the capturing phase.

Parameters
  • eventName {String} The event to emit
  • fn {Function} The listener callback

#removeListener(eventName, fn)

  • see events.EventEmitter

#setParent(emitter)

Adds an emitter as a parent to this object.

Parameters
  • emitter {hap.EventEmitter} The parent emitter

EventFacade

#val([value])

Sets or gets the current value. This value might be modified by any listener.

Parameters
  • value {Mixed} A value to set.