Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
branch: master
Fetching contributors…

Cannot retrieve contributors at this time

893 lines (552 sloc) 14.704 kB
.. include:: <s5defs.txt>
.. raw:: html
:file: includes/logo.html
===================
Intro to MochiKit
===================
.. raw:: LaTeX
:file: includes/logo.tex
:Author: Bob Ippolito
:Date: May 2006
:Venue: The Ajax Experience 2006
.. raw:: LaTeX
\newpage
What's MochiKit?
================
* Makes JavaScript suck less
* Provides browser workarounds
* Simplifies AJAX and DOM
* Plays nicely with other code
Another Library?!
=================
(July 2005)
Prototype:
no docs or tests, mangles built-ins
Dojo:
no docs or demos
MochiKit Design Goals
=====================
* Documentation
* DOCUMENTATION
* Lots of tests
* Stay out of the way (not a framework)
* Consistent and portable
Why MochiKit?
=============
* Good docs, well tested
* Async abstractions
* Painless DOM syntax
* Consistent browser events
* Python-like (think "standard library")
* Safari 2.0, Firefox 1.0, IE 6, Opera 8.5 (and others)
Why Not MochiKit?
=================
* No support for IE 5.5
* No widgets
* No animation, transitions, etc.
* ... MochiKit 1.4
MochiKit.Base
=============
* Beats some sense into JavaScript
* Provides analogs to a lot Python built-ins and object protocols
* This is the "suck less" part
toString Ambiguity
==================
* [1].toString() === '1'
* (1).toString() === '1'
* '1'.toString() === '1'
repr > toString
===============
* MochiKit provides repr() instead, just like Python.
* Unambiguous, extensible
MochiKit Interpreter
====================
.. raw:: html
:file: includes/interpreter.html
.. class:: handout
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
====================
* Most JavaScript comparisons based on toString
* [1] == [1] is false!
* compare(a, b) provides consistent results
* Extensible
JSON Serialization
==================
* serializeJSON(object) -> JSON string
* Extensible
Adapters?
=========
* Not a good idea to hack on built-in objects
* MochiKit doesn't always know what you want to do
* Adapters let you extend existing functions
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
===========
* Easily build URL query strings
* queryString(['foo', 'bar'], [1, 2]) == 'foo=1&bar=2'
* queryString({foo: 1, bar: 2}) == 'foo=1&bar=2'
queryString and DOM
===================
* queryString('formNode') == 'foo=1&bar=2', given::
<form id="formNode">
<input type="hidden" name="foo" value="1" />
<input type="text" name="bar" value="2" />
</form>
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.
* Works great on Arrays, but also on anything iterable.
* Anything with a ``next`` method is iterable, and the iteration stops when
StopIteration is thrown.
* Extensible
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
=================
* JavaScript Date objects aren't very convenient
* W3C profile ISO 8601 style timestamps are Good
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
===============
* JavaScript has no sprintf
* Thousands separators help readability
* Java's NumberFormat pattern syntax
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
================
* alert() sucks
* Debugging is hard enough
* FireBug not portable
* Venkman hard to use
* Microsoft Script Debugger....
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
====================
* MochiKit.Logging listener
* Can be used in-line or as a pop-up window
Manually creating a LoggingPane
===============================
Pop-up::
createLoggingPane()
Inline::
createLoggingPane(true)
Inline LoggingPane Example
==========================
.. raw:: html
:file: includes/logging_pane.html
.. class:: handout
In-line demo of the MochiKit LoggingPane.
MochiKit.DOM
============
* W3C bindings are painful
* Easily find, create, mangle DOM nodes
* Don't need $(s), automatic
* Works on responseXML too!
createDOM
=========
* Any object into a DOM node
* Strings to text, flattens iterators
* Extensible
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
===============
.. raw:: html
:file: includes/dominterpreter.html
.. class:: handout
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
===========
* DOM manipulation isn't as fast as innerHTML, but it's a LOT easier
* IE expects tables to have a TBODY
MochiKit.Color
==============
* Full CSS3 color model with alpha
* NSColor-like API (from Cocoa)
* Works in RGB, HSV, HSL
* Normalized to [0, 1.0]
Components to Color
===================
* Color.fromRGB(r, g, b, alpha=1.0)
* fromHSL, fromHSV
* Also {r: 1, g: 0, b: 0, a: 1}
String to Color
===============
Color.fromString(str):
Color from any valid CSS color description
- 'rgb(...)'
- 'hsl(...)'
- '#RRGGBB'
- 'blue'
DOM to Color
============
- Color.fromBackground(node)
- fromComputedStyle, fromText, ...
NSColor Colors
==============
Cocoa-based constructors for basic colors
- Color.whiteColor()
- blueColor, transparentColor, ...
Mixing Colors
=============
- color.blendedColor(otherColor, fraction)
- color.colorWithHue, colorWithLevel, ...
Color Components
================
Objects:
- color.asRGB(), asHSL, asHSV
Strings:
- color.toHexString(), toRGBString, toHSLString
MochiKit.Async
==============
* AJAX!
* Model based on Twisted
* XMLHttpRequest and timed events (setTimeout)
WTF is a Deferred?
==================
* A "promise" for a result
* Can be chained
* Model on any asynchronous platform
* Not "ideal" API, but no coroutines or threads
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
===============
* Crown jewel of MochiKit 1.3
* Sorry it took so long!
* Browsers totally suck at events
Browser Events Suck
===================
* IE is totally different
* IE's garbage "collector"
* Safari needs help
* They all disagree on pixel positions
* Key events seriously borked
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
===================
* Consistent event object!!
* e.type() is the event type
* e.target() is the event target
* e.mouse() has mouse coordinates
* e.key() for keyboard state
* e.modifiers() for keyboard modifiers
* e.stop() to stop
Mouse Events
============
.. raw:: html
:file: includes/draggable.html
.. class:: handout
The slide's logo will be dragged during this slide, while displaying live
pixel coordinates.
Keyboard Events
===============
.. raw:: html
:file: includes/key_events.html
.. class:: handout
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
===============
* Broadcast your own events!
* connect() and disconnect() are the same
* signal(src, signal, args...) to fire
MochiKit Support
================
- Check the documentation
- Ask on the mailing list
- Check the wiki/bug tracker
- #mochikit on irc.freenode.net
MochiKit on the Web
===================
Home page:
http://mochikit.com/
Bug tracker/Wiki:
http://trac.mochikit.com/
Subversion repository:
http://svn.mochikit.com/
Jump to Line
Something went wrong with that request. Please try again.