Skip to content

Commit

Permalink
- added documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
Nickolay Platonov committed Jan 13, 2011
1 parent 2c68275 commit 9a1f196
Show file tree
Hide file tree
Showing 6 changed files with 791 additions and 69 deletions.
300 changes: 266 additions & 34 deletions README.md
@@ -1,85 +1,317 @@
Name
====

JooseX.Observable - Some clever yet compact description
JooseX.Observable - Observable pattern as Joose Role


SYNOPSIS
========

// declaring our class
Class('JooseX.Observable', {
// Simple events

Class('My.Class', {
does : JooseX.Observable
})
var instance = new My.Class()
var handler = function (event, param1, param2) {
// event.source == instance
// param1 == 'foo'
// param2 == 'bar'
}
instance.on('event', handler, scope, { single : true, delay : 100 })
instance.fireEvent('event', 'foo', 'bar')

// Hierarchical events #1
var handler = function (event, param1, param2) {
// event.source == instance
// event.splat == 'event'
// param1 == 'foo'
// param2 == 'bar'
}

instance.on('/some/*', handler, scope, { single : true, buffer : 100 })
instance.emit('/some/event', 'foo', 'bar')
// Hierarchical events #2
var handler = function (event, param1, param2) {
// event.source == instance
// event.splat == [ 'long', 'event' ]
// param1 == 'foo'
// param2 == 'bar'
}

instance.on('/some/**', handler, scope, { single : true, buffer : 100 })
instance.fireEvent('/some/long/event', 'foo', 'bar')
// Bubbling
Class('Container', {
does : JooseX.Observable
})
// then instantiating it
var instance = new JooseX.Observable({

Class('Component', {
does : JooseX.Observable,
has : {
parentContainer : { required : true }
},
methods : {
getBubbleTarget : function () {
return this.parentContainer
}
}
})
// and doing something totally awesome with it :D
instance.method(param1, param2)
var container = new Container()
var component = new Component({
parentContainer : container
})

var handler = function (event, param1, param2) {
// event.source == component
// event.current == container
event.stopPropagation() // stop further bubbling
}

container.on('/some/**', handler, scope, { single : true, buffer : 100 })
component.fireEvent('/some/long/event', 'foo', 'bar')


INSTALLATION
============

From `npm`:

> [sudo] npm install joosex-observable

Tarballs are available for downloading at: http://search.npmjs.org/#/joosex-observable


SETUP
=====

In NodeJS:

require('task-joose-nodejs')
require('joosex-observable')


In browsers (assuming you've completed the 3.1 item from this [document](http://joose.github.com/Joose/doc/html/Joose/Manual/Installation.html)):

<script type="text/javascript" src="/jsan/Task/Joose/Core.js"></script>
<script type="text/javascript" src="/jsan/Task/JooseX/Observable/Core.js"></script>


DESCRIPTION
===========

`JooseX.Observable` is a stub for Joose-orientied JSAN modules.
`JooseX.Observable` is a Joose role, implementing the Observable pattern. To use it, just add it to your class declaration:

Class('My.Class', {
does : JooseX.Observable
})

In Observable pattern, class instances may notify the world about the changes in its state with "events".
One can say instance "fire" or "emit" the events. Other instances may "observe" such notifications ("listen to events").

To fire (emit) the event use `fireEvent` or `emit` methods (both are identical):

var instance = new My.Class()

instance.fireEvent('event', 'foo', 'bar')

The first argument to this method is the event name, all other arguments becomes the arguments of the event and will be available in the listeners.

ISA
===
To listen the event, use the method `on`:

None.
var handler = function (event, param1, param2) {
// event.source == instance
// param1 == 'foo'
// param2 == 'bar'
}
var listener = instance.on('event', handler, scope, { single : true, delay : 100 })

This method accept the event name, handler function, optional scope and optional options (see below for details). It returns the "listener" instance.

DOES
====
Each time the event being fired, all listeners with matching name will be activated. Their handler functions will always receive the instance of event as the 1st argument
(see above) and then other arguments from `fireEvent`. The object, which fired the event is available as the `source` property of the event.

None.
To remove the listener you can either pass it to the method `un`:

instance.un(listener)
or call its `remove` method:

TRAITS
======
listener.remove()

None.
or still use the `un` specifying the same handler and scope as during `on`:

instance.un('event', handler, scope)


EVENTS HIERARCHY
================

If the event name will contain slash(es) `/`, then it will be considered hierarchical. Hierarchical events behaves pretty much the same as usual events, with couple of additional features.

The very last segment of the event name will be treated as the "event name". Other segments will be treated as the "event channel". For example:

// fires the event "foo" in the channel "/"
instance.fireEvent('/foo')


// fires the event "bar" in the channel "/foo"
instance.fireEvent('/foo/bar')


// fires the event "" (empty string) in the channel "/foo/bar"
instance.fireEvent('/foo/bar/')

The same rules applies for the listeners, plus you can use the `*` and `**` wildcards:

// will be activated by "/foo" only
instance.on('/foo')


// will be activated by "/foo/bar" only
instance.on('/foo/bar')


// will be activated by "/foo/bar", "/foo/baz", "/foo/" (empty string)
// but not by "/foo/bar/baz" or "/bar"
instance.on('/foo/*')


// will be activated by "/foo/bar", "/foo/baz", "/foo/" (empty string), "/foo/bar/baz", "/foo/bar/baz/quix" etc
// but not by "/bar"
instance.on('/foo/**')

Hierarchical events are useful, when instance may emit *a lot* of different events, which can be categorized in groups, and listeners
need the ability to listen on the whole group of events.



EVENTS BUBBLING
===============

Additionally, all events bubbles (a-la DOM). This is useful, when the instance participate in the nested "part/whole" relationships and
the "whole" needs to listen the events from the inner "parts".

To use this feature, provide the implementation of the `getBubbleTarget` method in the consuming class.

If in the handler, you will call the `stopPropagation` method of the event, it will stop bubbling:

var handler = function (event, param1, param2) {
// event.source == component
// event.current == container
event.stopPropagation() // stop further bubbling
}
See also [JooseX.Observable.Event](Observable/Event.html) documentation.


ATTRIBUTES
==========

### attributeName
### suspendCounter

> `Number suspendCounter`
> `AttributeType attributeName`
> Initially set to 0. When this attribute is bigger than 0 the instance won't emit any events.
> Attribute description


METHODS
=======

### methodName
### on

> `method signature`
> `on(eventName, func, scope?, options?)`
> Method description
> This method create a new listener for the event `eventName`. Listener will activate the function `func` using either provided `scope` or the
event source as the scope. Optional `options` parameter should contain object with properties, corresponding to attributes of [JooseX.Observable.Listener](Observable/Listener.html)

> Returns an instance of [JooseX.Observable.Listener](Observable/Listener.html)
EXAMPLES
========
### un

Our class can be used like this:
> `un(eventName, func, scope)`
// then instantiating it
var instance = new JooseX.Observable({
})
> `un(listener)`
> This method will remove the listener from this instance. Either accept an instance of [JooseX.Observable.Listener](Observable/Listener.html) or the same arguments as
were used for `on`


### emit
### fireEvent

> `emit(eventName, param1, param2, ...)`
> `fireEvent(eventName, param1, param2, ...)`
> These methods are identical and both "fires" the event (activates all listeners with names matching to `eventName`). The handlers of the listeners will receive the
instance of [JooseX.Observable.Event](Observable/Event.html) as the 1st argument and the remaining parameters as other arguments


### hasListenerFor

> `hasListenerFor(eventName)`
> Returns boolean value, indicating whether this instance has listeners for the `eventName`. `eventName` may contain `*` and `**` wildcards.

### purgeListeners

> `purgeListeners()`
> Removes all listeners

### suspendEvents

> `suspendEvents()`
> This method increase the [suspendCounter] attribute and prevents any events from being emitted

### resumeEvents

> `resumeEvents()`
> This method decrease the [suspendCounter] attribute. As soon as it becomes 0 again, instance can emit events again.
and like that:

// then instantiating it
var instance = new JooseX.Observable({
})


GETTING HELP
Expand All @@ -97,7 +329,7 @@ SEE ALSO

Web page of this module: <http://github.com/SamuraiJack/JooseX-Observable/>

General documentation for Joose: <http://openjsan.org/go/?l=Joose>
General documentation for Joose: <http://joose.github.com/Joose/>


BUGS
Expand Down
2 changes: 1 addition & 1 deletion dist.ini
@@ -1,5 +1,5 @@
name = JooseX-Observable
abstract = Observable patter as Joose role
abstract = Observable pattern as Joose role

author = Nickolay Platonov <nplatonov@cpan.org>
license = LGPL_3_0
Expand Down

0 comments on commit 9a1f196

Please sign in to comment.