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 🙏

© 2026 – Pkg Stats / Ryan Hefner

afinity

v0.0.4

Published

Model/view/events object factory for modular user interface

Readme

afinity

Model/view/events object factory for modular user interface


Install

Method 1

Install as NPM module.

npm install afinity --save

And include via CommonJS/Browserify.

app = require 'afinity'

Method 2

The minified library found in dist folder can be included after jQuery.

<script src="afinity.min.js"></script>

Then it is exposed as afinity in the global scope.

app = afinity

Note

The library and examples are written in CoffeeScript for sweeter syntax, but it works well in vanilla JS also. Just throw in a healthy dose of parentheses, curly brackets, semicolons..


Overview

The main method is create, which takes three properties: model, view, and events.

obj = app.create
  model:
    counter: 0
  view:
    '#counter-view'
  events:
    'click .add': ->
      @set 'counter', @get()+1
    'click .subtract': ->
      @set 'counter', @get()-1

obj.on 'change:counter', ->
  console.log 'Counter changed to '+obj.get('counter')
  • Model is the data or state of the object
  • View is the HTML representation, with optional data-binding to model
  • Events include user actions like click and submit, as well as internal events

Each object:

  • is encapsulated
  • can publish/subscribe events to communicate with other objects
  • can be used as a prototype to clone similar objects
  • can contain child objects to create nested structure, i.e. collections

Object Methods

  • on, trigger
  • append, destroy

Model

obj = app.create
  model :
    message : 'Hello'

obj.set 'message', 'Hey'

Methods

  • get, set

Events

  • change
  • change:property

View templates

The HTML attribute data-bind is used to bind model property to view, and vice versa if it's an input element. All other templating logic like looping through collections, conditional states, must be handled by object methods, or in the context.

Template as string

Small templates may be given as a string.

obj = app.create
  model:
    counter: 0
  view:
    '<span data-bind="counter"></div>'
  increment: (value) ->
    @set 'counter', @get('counter')+(value or 1)
  decrement: (value) ->
    @set 'counter', @get('counter')-(value or 1)

obj.increment(5).decrement(10)

Template format and style

There are two template helpers html and css to encapsulate both template and style within the object. This can be useful for building reusable components.


{ form, input, button } = app.html
css = app.css

obj = app.create
  model:
    name: ''
    email: ''
  view:
    format:
      form ->
        input bind: 'name'
        input bind: 'email'
        button type: 'submit'
    style: css
      '&':
        border: '1px solid #ddd'
        'input, button':
          width: '100%'
  events:
    'submit': ->
      data = @get()
      # Do something with data

Template in document

The template can be already in the document.

<form id="contact-form">
  <input type="text" name="name">
  <input type="email" name="email">
  <button type="submit">Send</button>
</form>
obj = app.create view: '#contact-form'

If it's a form, the inputs are automatically bound as model properties.

Template in script tag

<script type="text/template" id="single-post">
  <article class="single-post">
    <h1 data-bind="title"></h1>
    <small data-bind="date"></small>
    <main class="post-content" data-bind="html=content"></main>
  </article>
</script>
Post = app.create view: '#single-post'

newPost = app.clone Post,
  title: 'New blog post'
  date: '2016-04-20'
  content: 'Lorem ipsum, lorem ipsum'

app.body.append '.post-list', newPost

View methods

  • $view

Events

Internal

  • create
  • change
  • append
  • remove

DOM

  • click, submit, keydown, etc.

Clones and children

  • append, each

Credit

Originally based on Agility.js by Artur B. Adib - http://agilityjs.com

Forked, pulled requests, modularized, extended, refactored and caffeinated