modularity-framework

Lightweight component-oriented Web UI framework

A modular clientside JavaScript controller micro-framework

Modularity is a micro-framework for lightweight component-oriented client-side JavaScript. It allows to compose functionally rich AJAX web sites in clean, intuitive, and testable ways out of well structured and reusable JavaScript components.

Modularity gives you the right amount of infrastructure to organize your clientside JavaScript around the logical parts of your web pages using JavaScript classes that are specialized for managing DOM and events. This results in maintainable architectures of loosely coupled JavaScript controller objects.

What makes Modularity stand out is that it scales very well with complexity, has a tiny footprint (1.3k compressed), is nicely testable, and overall does not get in the way of the expert developer.

You can easily combine Modularity controllers with your favorite templating and data management libraries, or any other jQuery or JavaScript plugin.

If some of the existing MVC frameworks fit your use case, use them! If your app is not primarily data driven, or want to stay more in control of what happens on your page and when, Modularity might be a good lightweight and general-purpose infrastructure to make your life easier.

Modularity provides a single helper class called Module. A module is a JavaScript class that manages a part of a web page. Examples for typical parts of webpages are a menu, a slideshow, a comment form, a button etc.

Each module is responsible for everything that happens inside its part of the web page.

  • making sure the DOM content is there
  • wiring up event handlers to the DOM
  • responding to events that get fired by DOM elements inside its web page part
  • notifying subscribers in the outside world about updates from inside this module
  • responding to messages that are sent from the outside world to this module

Let's build a button that displays how often it was clicked. It should also have a switch to reset the counter. All we need for it is an empty container element.

<button id="my_click_button"></button>

Let's define a module for it.

# A button that displays how often it was clicked. 
class CounterButton extends modularity.Module
 
  # Each module must be given its container as the first argument of the constructor. 
  # The container is the DOM element that contains all of the module content. 
  # 
  # Everything that is happening inside the container is the 
  # responsibility of this module. Nothing that happens outside of this 
  # container element is a concern for the module. Anything that this 
  # module does must happen inside the container. 
  constructor (container) ->
    super  # Every module must call the superclass constructor. 
 
    # Optionally create some DOM content, if it doesn't exist already. 
    # This could also be done with a templating library. 
    container.html """You have clicked me <span class="click_count">0</span> times.
                      <div class="reset"></div>"""
 
    # This DOM attribute makes the click counter element easier accessible. 
    # The @$ method runs jQuery only for elements inside this module's container. 
    @click_count_display = @$('.click_count')
 
    # A data attribute, representing how often has the button has been clicked so far. 
    @click_count = parseInt(@click_count_display.text())
 
    # An embedded module.  Modularity allows (and encourages) to compose modules 
    # out of other modules or raw DOM elements. 
    # 
    # In this case, the "ResetSwitch" module takes care of the "reset" switch 
    # for this button. We don't care how it does that. It could listen to 
    # mouse clicks, keyboard hotkeys, swiping gestures, or shaking of the 
    # mobile device that this page runs on etc. All of this functionality is 
    # encapsulated in the "ResetSwitch" module. 
    # All we care about here is that the "ResetSwitch" module fires a 
    # "triggered" event when the user activated the reset switch. 
    @reset_switch = new ResetSwitch '.reset'
 
    # Automatically wire up event handlers. 
    # See https://github.com/kevgo/eventualize for how this works. 
    eventualize this
 
 
  # Called when the user clicks on this button. 
  on_container_click: =>
    @click_count++
    @update_click_count_display()
 
 
  # Called when the user triggers the 'reset' switch. 
  on_reset_switch_triggered: =>
    @click_count = 0
    @update_click_count_display()
 
 
  # Updates the click counter display with the current click count. 
  update_click_count_display: ->
    @click_count_display.html @click_count
 
    # Let's make this a bit fancy, and indicate with colors whether the 
    # button has been clicked enough. 
    if @click_count_display > 3
      @container.addClass 'green'
    else
      @container.removeClass 'green'

To instantiate our CounterButton, all we have to do is give it the container element:

new CounterButton '#my_click_button'

Similar to Ruby mixins, mixins in Modularity allow to include orthogonal functional aspects defined in separate objects into a class.

myMixin =
 
  # This will be called when an instance of a class that includes this mixin is created. 
  constructor: ->
 
  # This method will be available in every class that includes this mixin. 
  myMethod: ->
 
 
class MyModule extends Module
 
  @mixin myMixin
 
  constructor: (container) ->
 
    # The super constructor will call the mixin constructors here. 
    super
 
    # ... 
  • tell us about an idea for a new feature: https://github.com/kevgo/modularity-framework/issues
  • set up the development environment on your machine: npm install
  • run tests: npm test
  • release a new patch version: tools/release
  • compile a new release: gulp build (you should not do this manually, tools/release does this for you)
  • contribute some changes: unit-tested pull requests please! :heart_eyes_cat: