Class: Behavior back to top

Auto-instantiates widgets/classes based on parsed, declarative HTML.

Implements

Syntax

new Behavior([options]);

Arguments

  1. options - (object; optional) a key/value set of options

Options

Events

Usage

Behavior is applied to an element whenever you want to parse that element's DOM for filters declared in the HTML of that element. Behavior then finds all elements with a "data-behavior" property defined, invoking the filters named there. It will only invoke a filter once, so it's safe to run it more than once (if the DOM changes, for example).

Example Usage

var myBehavior = new Behavior();
myBehavior.apply(myContainerElement);

Example HTML

<div data-behavior="Accordion">
    <div class="toggle">Toggle 1</div>
    <div class="target">This area is controlled by Toggle 1.</div>
    <div class="toggle">Toggle 2</div>
    <div class="target">This area is controlled by Toggle 2.</div>
</div>

The above example will invoke the registered "Accordion" filter. See the section on Behavior.Filter below.

HTML properties

Behavior uses a clearly defined API to read HTML properties off the elements it configures. See BehaviorAPI for details as well as passMethod for methods that Behavior instances themselves provide.

Using Multiple Filters Together

It's possible to declare more than one data filter property for a single element (data-behavior="FormRequest FormValidator")

Using Your Behavior Instance as an Event Arbiter

When a filter performs an action that other filters might find useful to know about, the preferred usage is to fire an event on your Behavior instance via the behaviorAPI object passed to your filter. This provides a non-brittle way for filters to react to each other. For example, a Delegator that fetches new content via AJAX should fire the 'ammendDom' event. This event is also fired on the Behavior instances it's bound to (if it is). These two events are prescribed here, but you can use any you find useful. This allows filters to avoid referencing themselves.

Other events the author has used is to denote layout changes, layout:changed, layout:display, layout:size, etc.

Behavior Method: passMethod back to top

Defines a method that will be passed to filters. Behavior allows you to create a well defined API for filters to reference which increases their reusability. You define this API by explicitly passing named functions to them through the Behavior instance.

Syntax

myBehaviorInstance.passMethod(name, function);

Returns

Notes

By default, Behavior passes the following methods to filters in addition to the methods defined in the BehaviorAPI

You can add any other methods that your filters require. In general, your filters shouldn't reference anything in your environment except these methods and those methods defined in Behavior.Filter.

Behavior Method: passMethods back to top

Iterates over an object of key/values passing them to the passMethod method.

Syntax

myBehaviorInstance.passMethods(obj);

Arguments

  1. obj - (object) a set of name/function pairs to pass to the passMethod method.

Returns

Behavior Method: apply back to top

Applies all the behavior filters for an element and its children.

Syntax

myBehaviorInstance.apply(container[, force]);

Arguments

  1. container - (element) The DOM container to process behavior filters.
  2. force - (boolean; optional) if true elements that have already been processed will be processed again.

Returns

Behavior Method: applyFilter back to top

Applies a specific behavior filter to a specific element (but not its children).

Syntax

myBehaviorInstance.applyFilter(element, filter, [, force]);

Arguments

  1. container - (element) The DOM container to process behavior filters.
  2. filter - (object) An instance of Behavior.Filter.
  3. force - (boolean; optional) if true elements that have already been processed will be processed again.

Returns

Behavior Method: getFilter back to top

Given a name, return the registered filter.

Syntax

myBehaviorInstance.getFilter(name);

Arguments

  1. name - (string) The registered name of a filter.

Returns

Behavior Method: getPlugins back to top

Given a name, return the plugins registered for a filter by that name. See the section on Behavior.Filter for details.

Syntax

myBehaviorInstance.getPlugins(name);

Arguments

  1. name - (string) The registered name of a filter plugin.

Returns

Behavior Method: cleanup back to top

Garbage collects the specified element, cleaning up all the filters applied to it. This should be invoked when you delete an element from the DOM. When you cleanup an element its children are also garbage collected.

Syntax

myBehaviorInstance.cleanup(element);

Arguments

  1. element - An element to remove all attached filters.

Returns

Filters

Behavior applies all the registered filters to the element you specify (and its children). This requires that each element that should have a behavior applied name the filters it needs in its data-behavior property. It also means that every named filter must be registered.

Filters can be registered to an instance of Behavior or to the global Behavior namespace. So if you register a "Foo" filter globally, all instance of Behavior get that filter. If a specific instance of Behavior defines a "Foo" filter, then the local instance is used regardless of the presence of a global filter.

There are methods to add and remove filters to instances as well as to the global namespace.

Behavior Method: addFilter back to top

Add a new filter.

Syntax

myBehaviorInstance.addFilter(name, filter[, overwrite]);

Arguments

  1. name - (string) the name of the filter to add.
  2. filter - (function or object) See [Behavior.Filters][] below.
  3. overwrite - (boolean; optional) if true and there is already an existing filter by the given name, that filter will be replaced, otherwise the original is retained.

Returns

Behavior Method: addFilters back to top

Adds a group of filters.

Syntax

myBehaviorInstance.addFilters(obj[, overwrite]);

Arguments

  1. obj - (object) a key/value set of name/functions to be added.
  2. overwrite - (boolean; optional) if true and there is already an existing filter by the given name, that filter will be replaced, otherwise the original is retained.

Returns

Behavior Method: addPlugin back to top

Add a new plugin for a specified filter.

Syntax

myBehaviorInstance.addPlugin(filterName, pluginName, fn[, overwrite]);

Arguments

  1. filterName - (string) the name of the filter for the plugin.
  2. pluginName - (string) the name of the plugin.
  3. fn - (function) the function invoked after the filter is run against an element. See plugins below.
  4. overwrite - (boolean; optional) if true and there is already an existing plugin by the given name, that plugin will be replaced, otherwise the original is retained.

Returns

Behavior Method: addPlugins back to top

Adds a group of plugins.

Syntax

myBehaviorInstance.addPlugins(obj[, overwrite]);

Arguments

  1. obj - (object) a key/value set of name/functions to be added as plugins.
  2. overwrite - (boolean; optional) if true and there is already an existing plugin by the given name, that filter will be replaced, otherwise the original is retained.

Returns

Behavior Method: setFilterDefaults back to top

Sets the default values for a filter, overriding any defaults previously defined.

Syntax

myBehaviorInstance.setFilterDefaults(name, defaults);

Arguments

  1. name - (string) The registered name of a filter.
  2. defaults - (object) A key/value pair of defaults.

Behavior Method: setDelegator back to top

Stores a reference to a [Delegator][] instance that is returned by api.getDelegator().

Syntax

myBehavior.setDelegator(myDelegator);

Arguments

  1. myDelegator - (object) an instance of [Delegator][]

Returns

Behavior Method: getDelegator back to top

Returns a reference to the [Delegator][] instance that was set with setDelegator.

Syntax

myBehavior.getDelegator();

Returns

Static Methods back to top

Behavior Method: addGlobalFilter back to top

Add a new filter to the global Behavior namespace.

Syntax

myBehaviorInstance.addGlobalFilter(name, fn[, overwrite]);

Behavior Method: addGlobalFilters back to top

Adds a group of filters to the global Behavior namespace.

Syntax

myBehaviorInstance.addGlobalFilters(obj[, overwrite]);

Behavior Method: addGlobalPlugin back to top

Add a new global plugin for a specified filter.

Syntax

myBehaviorInstance.addGlobalPlugin(filterName, pluginName, fn[, overwrite]);

Behavior Method: addGlobalPlugins back to top

Adds a group of plugins to the global Behavior namespace.

Syntax

myBehaviorInstance.addGlobalPlugins(obj[, overwrite]);

Behavior Method: getFilter back to top

Given a name, return the registered global filter.

Syntax

Behavior.getFilter(name);

Arguments

  1. name - (string) The registered name of a filter.

Returns

Behavior Method: setFilterDefaults back to top

Sets the default values for a filter, overriding any defaults previously defined.

Syntax

Behavior.setFilterDefaults(name, defaults);

Arguments

  1. name - (string) The registered name of a filter.
  2. defaults - (object) A key/value pair of defaults.

Class: Behavior.Filter back to top

Behavior Filters are where you define what to do with elements that are marked with that filter. Elements can have numerous filters defined and filters can do anything with those elements that they like. In general, filters should only alter the element given, though it is possible to have elements that relate to others (for example, an Accoridon filter might set up an instance of Fx.Accordion using children that are the togglers and sections).

Typically filters allow for configuration using HTML5 data- properties, classes, and element attributes. See the BehaviorAPI which automates the reading of these properties.

An important rule of filters is that they cannot know about each other or be in any way dependent on each other. When two filters need to be managed differently when both are present, use a plugin (this should be rare).

Filters are typically not created with the constructor (i.e. new Behavior.Filter) but instead with the addFilter/addFilters methods defined on the Behavior instance or the addGlobalFilter/addGlobalFilters methods on the Behavior namespace.

Filters nearly always return instances of classes (this is essentially their purpose). It's not a requirement, but it is generally preferred.

Example

Behavior.addGlobalFilters({
    Accordion: function(element, api) {
        var togglers = element.getElements(api.get('togglers'));
        var sections = element.getElements(api.get('sections'));
        if (togglers.length == 0 || sections.length == 0) api.fail('There are no togglers or sections for this accordion.');
        if (togglers.length != sections.length) api.warn('There is a mismatch in the number of togglers and sections for this accordion.')
        var accordion = new Fx.Accordion(togglers, sections);
        api.onCleanup(function() {
            accordion.detach();
        });
        return accorion; //note that the instance is always returned!
    }
});

/* the matching HTML
<div data-behavior="Accordion" data-Accordion-togglers=".toggle" data-Accordion-sections=".section">
    <div class="toggle">Toggle 1</div>
<div class="target">This area is controlled by Toggle 1.</div>
</div> */

In the example above our filter finds the sections and togglers and validates that there is at least one of each. If there aren't it calls api.fail - this stops the filter's execution and Behavior.js catches it and calls its onError event (which defaults to console.error). It also checks if the number of togglers and the number of sections are equal and calls api.warn if they are off. This does not top execution; it only fires the onWarn event on Behavior (which defaults to console.warn).

Advanced Filters

A simple filter is just a function and a name ("Accordion") and the function that creates accordions given an element and the api object. This is fine, but it's possible to express more complex configurations. Example:

Behavior.addGlobalFilters({
    Accordion: {
        //if your filter does not return an instance of this value Behavior will throw an error
        //which is caught and logged by default
        returns: Accordion,
        require: ['togglers', 'togglers'],
        //or
        requireAs: {
            togglers: String,
            someNumericalValue: Number,
            someArrayValue: Array
        },
        //you wouldn't define defaults for required values, but this is just an example
        defaults: {
            togglers: '.toggler',
            sections: '.sections',
            initialDisplayFx: false
        },
        //simple example:
        setup: function(element, API){
            var togglers = element.getElements(api.get('togglers'));
            var sections = element.getElements(api.get('sections'));
            if (togglers.length == 0 || sections.length == 0) api.fail('There are no togglers or sections for this accordion.');
            if (togglers.length != sections.length) api.warn('There is a mismatch in the number of togglers and sections for this accordion.')
            var accordion = new Fx.Accordion(togglers, sections,
                api.getAs({
                    fixedHeight: Number,
                    fixedWidth: Number,
                    display: Number,
                    show: Number,
                    height: Boolean,
                    width: Boolean,
                    opacity: Boolean,
                    alwaysHide: Boolean,
                    trigger: String,
                    initialDisplayFx: Boolean,
                    returnHeightToAuto: Boolean
                })
            );
            api.onCleanup(function() {
                accordion.detach();
            });
            return accorion; //note that the instance is always returned!
        },
        //don't instantiate this value until the user mouses over the target element
        delayUntil: 'mouseover,focus',
        //OR delay for a specific period
        delay: 100,
        //OR let me initialize the function manually
        initializer: function(element, API){
            element.addEvent('mouseover', API.runSetup); //same as specifying event
            //or
            API.runSetup.delay(100); //same as specifying delay
            //or something completely esoteric
            var timer = (function(){
                if (element.hasClass('foo')){
                    clearInterval(timer);
                    API.runSetup();
                }
            }).periodical(100);
            //or
            API.addEvent('someBehaviorEvent', API.runSetup);
        });
    }
});

In the long-form example above, we see that filters can be passed as objects that map to the config option in the Behavior.Filter constructor arguments. (see Behavior.Filter's constructor) below.

Accessing passed methods

Behavior has a way to define API methods passed to filters for their use. To use these methods, access them in the second argument passed to your filter function:

Behavior.addGlobalPlugins({
    MeasureOnResize: function(element, api) {
        api.addEvent('resize', updater);
        api.onCleanup(function(){
            api.removeEvent('resize', updater);
        });
    }
});
var myBehaviorInstance = new Behavior();
myBehaviorInstance.apply(document.body); //applies all filters named in your content
//let's assume there's an element with the data-behavior property set to MeasureOnResize
myBehaviorInstance.fireEvent('resize');

As you can see in the example above, we add an event whenever the Behavior instance fires a "resize" method. We also clean up that event with the markForCleanup method which is passed through the api object as "onCleanup".

Behavior.Filter constructor back to top

While is common (and recommended) for filters to be declared using Behavior's addFilter method it's possible to create a filter on its own.

Syntax

new Behavior.Filter(name, filter);

Arguments

  1. name - (string) The name of this filter. This is not used directly by the filter, though Behavior instances use it. Stored as this.name on the instance of the filter.
  2. filter - (function or object) Can be a single function or an object with the config options listed below. The function (which must be present either as the argument or as the .setup property on the object) expect to be invoked with an element and an instance of BehaviorAPI passed to it. Filters in general expect this API object to be provided by a Behavior instance which also adds additional methods (see Behavior.passMethod) for more details.

Configuration

If the second argument passed to the constructor is an object, the following options are specified:

Note

You can namespace your filters to avoid conflicts. Simply give your filter a name with dots in it (data-behavior="Foo.Bar") and then reference any arguments with dashes (data-foo-bar-options="...").

Behavior.Filter Method: markForCleanup back to top

Adds a function to invoke when the element referenced is cleaned up by the Behavior instance. Note that Behavior passes this method through as "onCleanup" in it's API object.

Syntax

myBehaviorFilter.markForCleanup(element, fn);

//more commonly inside a filter:
api.onCleanup(fn); //element is not specified on the api object

Arguments

  1. element - The element passed in to your filter function; the element with the data-behavior applied to it.
  2. fn - (function) the function invoked when that element is garbage collected.

Behavior.Filter Method: cleanup back to top

Garbage collects the specific filter instance for a given element. This is typically handled by the Behavior instance when you call its cleanup method.

Syntax

myBehaviorFilter.cleanup(element);

//more commonly
myBehaviorInstance.cleanup(container);
//here the container can be any element that is being removed from the DOM
//all its children that have had filters applied will have their cleanup method run

Arguments

  1. element - The element passed in to your filter function; the element with the data-behavior applied to it.

Filter Plugins back to top

Filter Plugins are identical to regular filters with the exception that they are invoked only when the filter they are altering is invoked and always after that. Filters do not have any guarantee that they will be invoked in any given order, but plugins are always guaranteed to be invoked after the filter they reference. More specifically, they are always invoked after all the filters on an element are invoked. If an element has two filters (A and B) and each of these filters have plugins (A1 and B1) the invocation order will be A, B, A1, B1.

Example

Behavior.addFilter('Mask', function(element, api){
    var maskInstance = new Mask(element);
    //this is silly
    var events = {
        mouseover: maskInstance.show.bind(maskInstance),
        mouseout: maskInstance.hide.bind(maskInstance)
    };
    element.addEvents(events);
    api.onCleanup(function(){
        element.removeEvents(events);
    });
    return maskInstance; //note that we return the instance!
});

Behavior.defineGlobalPlugin('Mask', 'AlertOnMask', function(element, api, maskInstance){
    //also silly
    var aleter = function(){ alert('the mask is visible!'); };
    maskInstance.addEvent('show', alerter);
    api.onCleanup(function(){
        maskInstance.removeEvent('show', alerter);
    });
});

The above example is guaranteed to always run after the "Mask" filter. You can define a plugin for a plugin just as well; simply name the plugin as the first argument (you could create a plugin for the above example by making a plugin for "AlertOnMask"). Plugin setup functions are passed not only the target element and the api object but also the instance returned by the filter they augment.

Element Methods

Behavior implements the following helper methods on the Element prototype.

Element Method: addBehaviorFilter back to top

Adds a data filter to the element.

Syntax

myElement.addBehaviorFilter(name);

Arguments

  1. name - (string) The name of the data filter to add.

Returns

Element Method: removeBehaviorFilter back to top

Removes a data filter to the element.

Syntax

myElement.removeBehaviorFilter(name);

Arguments

  1. name - (string) The name of the data filter to remove.

Returns

Element Method: getBehaviors back to top

Gets an array of data filters specified on an element.

Syntax

myElement.getBehaviors();

Returns

Element Method: hasBehavior back to top

Returns true if the element has the specified data filter.

Syntax

myElement.hasBehavior(name);

Arguments

  1. name - (string) The name of the data filter to check for.

Returns

Element Method: getBehaviorResult back to top

Filters generally return the instance of the widget they instantiate. This method allows you to access that widget.

Syntax

myElement.getBehaviorResult(name);

Arguments

  1. name - (string) The name of the data filter to get the result of.

Returns