Intro to MochiKit

Author: Bob Ippolito
Date: May 2006
Venue:The Ajax Experience 2006

What's MochiKit?

Another Library?!

(July 2005)

Prototype:
no docs or tests, mangles built-ins
Dojo:
no docs or demos

MochiKit Design Goals

Why MochiKit?

Why Not MochiKit?

MochiKit.Base

toString Ambiguity

repr > toString

MochiKit Interpreter

In-line demo of the MochiKit interpreter example. The advantages of repr vs. toString and some of the interpreter's features will be demonstrated during this slide.

Unreliable Operators

JSON Serialization

Adapters?

Adapting

name:
unique identifier for your adapter
check:
should wrap be called?
wrap:
performs the operation

DOM Comparator Example

Register HTML-based comparator for DOM nodes:

function isDOMNode(node) {
    return typeof(node.nodeType) == 'number';
}

function compareDOMNodes(a, b) {
    return compare(a.innerHTML, b.innerHTML);
}

registerComparator('compareDOM',
    isDOMNode, compareDOMNode);

queryString

queryString and DOM

Mangling Objects

merge(obj[, ...]):
New object, every prop:value of given objects
update(obj[, ...]):
In-place merge
updatetree(obj[, ...]):
Recursive update
setdefault(obj[, ...]):
update, but no overwrite

Object Introspection

keys(obj):
Array of obj's properties
items(obj):
Array of obj's [property, value]

Function Functions

bind(fn, self[, arg...]):
fn.apply(self, concat(arg..., arguments))
method(self, fn[, arg...]):
convenience form for bind
itemgetter(name):
obj[name]

Array Functions

Array missing lots of useful functionality

concat(lst[, ...]):
concatenates Arrays
extend(self, seq, skip=0):
extends Array in-place
flattenArguments(args[, ...]):
recursively flatten arguments to single Array

Array Searching

findValue(lst, value):
finds index of value
findIdentical(lst, value):
finds index of identical value
listMin(lst):
finds least item in lst
listMax(lst):
finds greatest item in lst

Higher-order Array

filter(func, lst):
Array where funcn(lst[n])
map(func, lst):
[func(lst[0]), ...]
keyComparator(key):
compare(a[key], b[key])

MochiKit.Iter

MochiKit.Iter provides generalized iteration, like Python's iteration protocol and itertools module.

Collapsing Iterators

exhaust(iterable):
Iterate and ignore results
list(iterable):
new Array
sorted(iterable):
sorted Array
sum(iterable, start=0):
Return start plus sum of items

Iterating Iterables

The hard way:

var itr = iter(iterable);
try {
    while (true) {
        var item = itr.next();
        // ...
    }
} catch (e) {
    if (e != StopIteration) throw e;
}

Sane Iterable Iteration

The easy way:

forEach(iterable, function (item) {
    // ...
})

Infinite Iterators

count(n=0):
n, n + 1, n + 2, ...
cycle(iterable):
while (1) { iterable[0], ... }
repeat(item):
item, item, item, item, ...

MochiKit.DateTime

ISO Dates

isoDate(str):
Date object from ISO 8601 date string
toISODate(date):
Date object to ISO 8601 date string

American Dates

americanDate(str):
MM/DD/YYYY to a Date object
toAmericanDate(date):
Date object to M/D/YYYY
toPaddedAmericanDate(date):
Date object to MM/DD/YYYY

Time and Timestamps

isoTimestamp(str):
YYYY-MM-DDThh:mm:ssZ to Date object
toISOTime(date):
Date object to hh:mm:ss
toISOTimestamp(date, realISO=false):
Date object to a YYYY-MM-DD hh:mm:ss (or YYYY-MM-DDThh:mm:ssZ)

MochiKit.Format

Whitespace Assassins

lstrip(str):
strip leading whitespace
rstrip(str):
strip trailing whitespace
strip(str):
strip leading and trailing whitespace

Number Formatting

numberFormatter(pattern):
new function that formats numbers to pattern

Currency Formatter Example

Currency:

>>> money = numberFormatter('$###,###.##')
>>> money(1234567.89)
"$1,234,567.89"

Percent Formatter Example

Percent:

>>> percent = numberFormatter('###,###%')
>>> percent(123.45)
"12,345%"

MochiKit.Logging

Simple Logging

log(msg):
Logs a message at the INFO level

logDebug, logWarning, logError, logFatal...

Logs Are Where?

Native console:
Safari, FireBug, Opera
Logging listener(s):
functions called with log message objects

Bookmarklet Debugging

Pop-up MochiKit.LoggingPane:

javascript:logger.debuggingBookmarklet()

MochiKit.LoggingPane

Manually creating a LoggingPane

Pop-up:

createLoggingPane()

Inline:

createLoggingPane(true)

Inline LoggingPane Example

Where's the LoggingPane?

In-line demo of the MochiKit LoggingPane.

MochiKit.DOM

createDOM

createDOM Example

createDOM(tagName, attributes, contents...)

A simple list:

var node = createDOM('ul', null,
    createDOM('li', null, 'first'),
    createDOM('li', null, 'second'));

Renders as:

<ul><li>first</li><li>second</li></ul>

Less Ugly

Use aliases instead, supports common tags:

var node = UL(null,
    LI('first'),
    LI('second'));

Flattening for the DOM

Functional style handy for DOM creation:

var items = ['first', 'second'];
var node = UL(null, map(LI, items));

Attributes

First parameter is either an object (attributes), or a string (text node):

var classes = repeat({'class': 'itemclass'});

var items = ['first', 'second'];

var node = UL({'class': 'listclass'},
    map(LI, classes, items));

Alternating

MochiKit.Iter good for table rows:

var classes = cycle(
    {'class': 'even'},
    {'class': 'odd'});

var items = ['first', 'second'];

var node = UL(null,
    map(LI, classes, items));

Interpreter DOM

Another in-line interpreter demo, this time showing off MochiKit's DOM support.

Scraping Text

Scraping text is useful for progressive enhancement...

HTML:

<span id="scrape_me">text is <b>here</b></span>

JavaScript:

>>> scrapeText('scrape_me');
"text is here"

Forms

HTML:

<form id="formNode">
    <input type="hidden" name="foo" value="1" />
    <input type="hidden" name="bar" value="2" />
</form>

JavaScript:

>>> formContents('formNode')
[["foo", "bar"], ["1", "2"]]

Manipulating DOM

appendChildNodes(parent, children...):
Add nodes via createDOM
replaceChildNodes(parent, children...):
Remove all, then append
swapDOM(dest, src):
Replace dest with src (or remove)

DOM Attributes

setNodeAttribute(node, attr, value):
node attribute attr=value
updateNodeAttributes(node, attrs):
node attributes from object attrs

DOM Gotchas

MochiKit.Color

Components to Color

String to Color

Color.fromString(str):
Color from any valid CSS color description

DOM to Color

NSColor Colors

Cocoa-based constructors for basic colors

Mixing Colors

Color Components

Objects:

Strings:

MochiKit.Async

WTF is a Deferred?

Trivial Deferreds

succeed(value):
successful Deferred from value
fail(error):
failed Deferred from error
maybeDeferred(func, arguments..):
Deferred from func(args..) call

Timed Events

wait(seconds, value):
Deferred that waits
callLater(seconds, func, arguments...):
Deferred that waits, then calls

Network Events

doSimpleXMLHttpRequest(url):
Deferred from XMLHttpRequest GET
loadJSONDoc(url):
Deferred from XMLHttpRequest GET then eval
sendXMLHttpRequest(req, data):
Deferred from async XMLHttpRequest

Deferred Usage

Fetch a JSON document:

function gotDocument(json) {
    // ...
}
var d = loadJSONDoc("example.json");
d.addCallback(gotDocument);
d.addErrback(logError);

Result Chaining

loadJSONDoc implementation:

var d = doSimpleXMLHttpRequest(url);
d.addCallback(evalJSONDoc);
return d;

Uses Deferred's chained results

Deferred Chaining

Returning a Deferred from a callback will "pause" the callback chain:

function gotDocument(json) { /* ... */ }
function delay(res) { return wait(2.0, res); }
var d = loadJSONDoc('example.json');
d.addCallback(delay);
d.addCallback(gotDocument);

MochiKit.Signal

Browser Events Suck

connect to the DOM

Works everywhere:

function myClick(e) {
    var mouse = e.mouse();
    log('page coordinates: ' + mouse.page);
    log('client coordinates: ' + mouse.client);
}
connect('element_id', 'onclick', myClick);

Custom Event Object

Mouse Events

The slide's logo will be dragged during this slide, while displaying live pixel coordinates.

Keyboard Events

Event Key Code Key String
onkeydown - -
onkeyup - -
onkeypress - -

Modifiers

Shift Ctrl Alt Meta

An in-line version of the key_events demo will be shown during this slide, showing capture of onkeypress, onkeydown, onkeyup events. Also shows the consistent naming of keys.

Signal Anything

MochiKit Support

MochiKit on the Web

Home page:
http://mochikit.com/
Bug tracker/Wiki:
http://trac.mochikit.com/
Subversion repository:
http://svn.mochikit.com/