Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Comparing changes

Choose two branches to see what's changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
base fork: jldailey/BlingJS
base: 251fc28985
...
head fork: jldailey/BlingJS
compare: 369cbc0ddf
Checking mergeability… Don't worry, you can still create the pull request.
  • 6 commits
  • 3 files changed
  • 0 commit comments
  • 1 contributor
Showing with 518 additions and 488 deletions.
  1. +497 −477 bling.coffee
  2. +20 −10 tests/bling.coffee
  3. +1 −1  tests/domjs
View
974 bling.coffee
@@ -23,7 +23,7 @@
# We need a few things to get started:
-# A safe reference to `console.log()`:
+# A safe reference to `$.log()`:
log = (a...) ->
try return console.log.apply console, a
alert a.join(", ")
@@ -39,11 +39,15 @@ extend ?= (a, b) ->
if v? then a[k] = v
a
-
+# A wrapper for Object.defineProperty that changes the defaults
+defineProperty = (o,name,opts) ->
+ Object.defineProperty o,name, extend({
+ configurable: true
+ enumerable: true
+ }, opts)
# Type System
# -----------
-
# The type system is built around a _type classifier_. Initially, this
# will only know how to match types (and the order to check them in).
# Later, the type-instance that results from classification will be
@@ -61,7 +65,7 @@ isType = (T, o) ->
Object::toString.apply(o) is "[object #{T}]" or
isType T, o.__proto__
-# `inherit(parent, child)` is similar to Extend, except it works by
+# `inherit(parent, child)` is similar to extend, except it works by
# inserting the parent as the prototype of the child _instance_. This is unlike
# coffee's `class X extends Y`, because it expects the target `child`
# to be an _instance_, and the `parent` can either be an _instance_ or a
@@ -95,16 +99,13 @@ type = (->
# * Put the type check in order (if it isn't already).
order.unshift name if not (name of cache)
# * inherit from the base type and store in the cache.
- cache[data.name = name] = inherit base, data
+ cache[data.name = name] = if (base isnt data) then (inherit base, data) else data
# Later, plugins can `extend` previously registered types with new
# functionality.
_extend = (name, data) ->
- # If explicitly passed a null for the name, extend base type
- if data? and not name?
- extend base, data
# The `name` should be of a registered type (a key into the cache)
- else if typeof name is "string"
+ if typeof name is "string"
# But, if you attempt to extend a type that was not registered yet,
# it will be automatically registered.
cache[name] ?= register(name, {})
@@ -125,7 +126,7 @@ type = (->
# Now, register all the built-in types. These checks are
# executed in _reverse order_, so the first listed here, `"unknown"`,
# is always checked last.
- register "unknown", match: -> true
+ register "unknown", base
# This implies that the 'simplest' checks should be registered
# first, and conceptually more specialized checks would get added
# as time goes on (so specialized type matches are preferred).
@@ -149,7 +150,7 @@ type = (->
register: register
lookup: lookup
extend: _extend
- match: (t, o) -> cache[t]?.match.call o, o
+ is: (t, o) -> cache[t]?.match.call o, o
# Example: Calling $.type directly will get you the simple name of the
# best match.
@@ -182,14 +183,14 @@ type = (->
# 1. _The copy is shallow_; creating partially-shared state between
# instances.
-# 2. _There is a copy at all_; one should avoid copying in critical
+# 2. _There is a copy at all_; it's nice to avoid copying in critical
# sections whenever possible.
# 3. _It replaces the return value of the constructor_; reducing
# flexibility in implementations.
# So, the Bling constructor should not be called as `new Bling`,
-# and this means our assignment to a symbol (`$`) remains simple.
-class Bling extends Array
+# and as a bonus our assignment to a symbol (`$`) remains simple.
+class Bling
constructor: (selector, context = document or {}) ->
# Since we have this nice Type system, our constructor is succinct:
# 1. Classify the type.
@@ -235,8 +236,8 @@ class Bling extends Array
['$','name'].forEach (k) -> delete plugin[k]
# Now put everything else on the Bling prototype
extend @::, plugin
- # Finally, add default global versions of anything that
- # doesn't have one already.
+ # Finally, add root-level wrappers for anything that doesn't
+ # have one already.
( @[key] or= (a...) => (@::[key].apply $(a[0]), a[1...]) ) for key of plugin # and gets a default global implementation
if opts.provides? then @provide opts.provides
catch error
@@ -273,18 +274,17 @@ class Bling extends Array
@provides: (needs, f) -> (a...) -> r=f(a...); Bling.provide(needs); r
- # Adding "bling" to the Type System
- # ---------------------------------
+ #### Registering the "bling" type.
# First, we give the basic types the ability to turn into something
- # array-like, for use in the constructor.
+ # array-like, for use by the constructor.
- # By default, if we don't know any better way, we just stick the
+ # If we don't know any better way, we just stick the
# thing inside a real array.
- type.extend null, array: (o) -> [o]
# But where we do know better, we can provide more meaningful
# conversions. Later, in the DOM section, we will extend
# this further to know how to convert "html", "node", etc.
type.extend
+ unknown: { array: (o) -> [o] }
# Null and undefined values convert to an empty array
null: { array: (o) -> [] }
undefined: { array: (o) -> [] }
@@ -302,18 +302,22 @@ class Bling extends Array
hash: (o) -> o.map(Bling.hash).sum()
string: (o) -> Bling.symbol + "([" + o.map(Bling.toString).join(", ")+ "])"
+Bling.prototype = []
# Plugins
-# ==============
-# Quickly set up a namespace that protects `$`, so we can safely use
-# short-hand in all of our plugins.
+# =======
+# Now that we have a way to load plugins and express dependencies
+# between them, all future code will come in a plugin.
+#
+# For the rest of this file, set up a namespace that protects `$`,
+# so we can safely use short-hand in all of our plugins.
(($) ->
#### Types plugin
- # Exposes the type system.
+ # Exposes the type system publicly.
$.plugin
- provides: "types"
+ provides: "type"
, ->
$:
inherit: inherit
@@ -324,11 +328,10 @@ class Bling extends Array
# `$.type([])` equals `"array"`.
type: type
# `$.is("function", ->)` equals true/false.
- is: type.match
+ is: type.is
isSimple: (o) -> type(o) in ["string", "number", "bool"]
isEmpty: (o) -> o in ["", null, undefined]
-
# Symbol Plugin
# -------------
# Symbol adds a dynamic property: Bling.symbol, which contains the
@@ -350,7 +353,7 @@ class Bling extends Array
symbol = null
cache = {}
(g = window ? global).Bling = Bling
- Object.defineProperty $, "symbol",
+ defineProperty $, "symbol",
set: (v) ->
g[symbol] = cache[symbol]
cache[symbol = v] = g[v]
@@ -373,6 +376,12 @@ class Bling extends Array
a.push @substring(i,j)
i = j + 1
a
+ # Find the last index of character `c` in the string `s`.
+ String::lastIndexOf or= (s, c, i = -1) ->
+ j = -1
+ j = i while (i = s.indexOf c, i+1) > -1
+ j
+
# Make sure we have Array functions: `join`.
Array::join or= (sep = '') ->
n = @length
@@ -446,7 +455,7 @@ class Bling extends Array
# Note that this reverses the order of _n_ and _f_
# intentionally. Throughout this library, the convention is
# to put the simple things first, to improve code flow:
- # > `$.delay 5, () ->` vs. `$.delay (() -> ), 5`
+ # > `$.delay 5, () ->` is better than `$.delay (() -> ), 5`
(n, f) ->
if $.is("function",f) then timeoutQueue.add(f, n)
cancel: -> timeoutQueue.cancel(f)
@@ -467,25 +476,22 @@ class Bling extends Array
provides: "core"
, ->
- # A functor that will read property `p` from some object later.
- gettor = (prop) -> -> if $.is("function",v = @[prop]) then $.bound(@,v) else v
- # A helper that will recursively split `p` on `.` and map a gettor
- # to read a set of complex `p` values from an object.
- selector = (p) ->
- if (i = p.indexOf '.') > -1 then @select(p.substr 0,i).select(p.substr i+1)
- else @map(gettor p)
- # See: `$.select`.
-
- Object.defineProperty $, "now",
+ defineProperty $, "now",
get: -> +new Date
+ # Negative indices should work the same everywhere.
+ index = (i, o) ->
+ i += o.length while i < 0
+ Math.min i, o.length
+
return {
$:
log: log
assert: (c, m="") -> if not c then throw new Error("assertion failed: #{m}")
+ coalesce: (a...) -> $(a).coalesce()
# Get a new set containing only the i-th element of _this_.
- eq: (i) -> $([@[i]])
+ eq: (i) -> $([@[index i, @]])
# Call a function on every item in _this_.
each: (f) -> (f.call(t,t) for t in @); @
@@ -526,6 +532,8 @@ class Bling extends Array
null
# Swap item i with item j, in-place.
swap: (i,j) ->
+ i = index i, @
+ j = index j, @
if i isnt j
[@[i],@[j]] = [@[j],@[i]]
@
@@ -537,14 +545,17 @@ class Bling extends Array
@
# Get a new set of properties from every item in _this_.
- select: (a...) ->
+ select: (->
+ # A helper that will read property `p` from some object later.
+ getter = (prop) -> -> if $.is("function",v = @[prop]) then $.bound(@,v) else v
+ # Recursively split `p` on `.` and map the getter helper
+ # to read a set of complex `p` values from an object.
# > `$([x]).select("name") == [ x.name ]`
# > `$([x]).select("childNodes.1.nodeName") == [ x.childNodes[1].nodeName ]`
- return switch (n = a.length)
- # Select nothing, get nothing.
- when 0 then $()
- # Select one property, get a list of those values.
- when 1 then selector.call @, a[0]
+ select = (p) ->
+ if (i = p.indexOf '.') > -1 then @select(p.substr 0,i).select(p.substr i+1)
+ else @map(getter p)
+ )()
# Replace any false-ish items in _this_ with _x_.
# > `$("<a>").select('parentNode').or(document)`
@@ -553,42 +564,41 @@ class Bling extends Array
# Assign the value _v_ to property _b_ on every
# item in _this_.
zap: (p, v) ->
- # `zap` supports the name dot-delimited property name scheme
+ # `zap` supports the same dot-delimited property name scheme
# that `select` uses. It does this by using `select`
# internally.
- i = 0
- # If there is a dot in the name, zoom to the _last_ dot.
- i = p.indexOf(".",i) while i > -1
- if i > -1
- # Use `select` to find the head portion, the tail should be
+
+ # Find the last "." in `p` so we can split into a head (to
+ # send to `select`) and a tail (a simple value to assign to).
+ i = p.lastIndexOf "."
+
+ if i > 0
+ # Use `select` to fetch the head portion, the tail will be
# a single property with no dots, which we recurse on (into
# a lower branch next time).
- return @select(p.substr(0, i)).zap(p.substr(i+1), v)
- # If _v_ is a sequence of values, they are striped across each
- # item in _this_.
- if $.is "array", v then @each -> @[p] = v[++i % v.length] # i starts at -1 because of the failed indexOf
- # If _v_ is a function, map and set each item's property,
- # akin to: `x[p] = v(x[p])`.
- else if $.is "function", v then @zap p, @select(p).map v
- # Anything else, scalars, objects, null, anything, get
- # assigned directly to each item in this.
- else @each -> @[p] = v
+ head = p.substr 0,i
+ tail = p.substr i+1
+ @select(head).zap tail, v
+ return @
+ switch $.type(v)
+ # If _v_ is a sequence of values, they are striped across each
+ # item in _this_.
+ when "array","bling" then @each -> @[p] = v[++i % v.length]
+ # If _v_ is a function, map and set each item's property,
+ # akin to: `x[p] = v(x[p])`.
+ when "function" then @zap p, @select(p).map(v)
+ # Anything else, scalars, objects, null, anything, get
+ # assigned directly to each item in this.
+ else @each -> @[p] = v
+ @
# Get a new set with only the first _n_ items from _this_.
- # Negative _n_ counts from the end. `take(1)` returns a set with
- # one item.
take: (n = 1) ->
- nn = @length
- start = 0
- end = Math.min n|0, nn
- if n < 0
- start = Math.max 0, nn+n
- end = nn
- $( @[i] for i in [start...end] )
+ end = Math.min n, @length
+ $( @[i] for i in [0...end] )
# Get a new set with every item except the first _n_ items.
- # Negative _n_ counts from the end. Always returns a set.
skip: (n = 0) ->
start = Math.max 0, n|0
$( @[i] for i in [start...@length] )
@@ -601,9 +611,8 @@ class Bling extends Array
slice: (start=0, end=@length) -> # .slice(/i/, [/j/]) - get a subset of _this_ including [/i/../j/-1]
# negative indices work like in python: -1 is the last item, -2 is second-to-last, null means inclusive
- n = @length
- start += n if start < 0
- end += n if end < 0
+ start = index start, @
+ end = index end, @
$( @[i] for i in [start...end] )
extend: (b) -> @.push(i) for i in b; @
@@ -672,7 +681,7 @@ class Bling extends Array
@map -> if $.is "function", @ then @apply(context, args) else @
# Log one line for each item.
- log: (label) -> # .log([label]) - console.log([/label/] + /x/) for /x/ in _this_
+ log: (label) -> # .log([label]) - $.log([/label/] + /x/) for /x/ in _this_
if label
$.log(label, @, @length + " items")
else
@@ -688,6 +697,7 @@ class Bling extends Array
# All the stuff you need to use blings as vectors in linear algebra.
$.plugin
provides: "math"
+ depends: "core"
, ->
$:
# Get an array of numbers.
@@ -732,16 +742,16 @@ class Bling extends Array
depends: "function"
provides: "string"
, ->
- #### $.toString
- # Extends the base type to allow for converting things
+ #### toString
+ # Extend the base type to allow for converting things
# to string based on their type. This is a separate system from the
# native Object.prototype.toString chain of methods.
- # First, extend the base type with a default `string` function
- $.type.extend null, string: (o) -> o.toString?() ? String(o)
- # Now, for each basic type, provide a basic `string` function.
- # Later, more complex types will be added by plugins.
$.type.extend
+ # First, extend the base type with a default `string` function
+ unknown: { string: (o) -> o.toString?() ? String(o) }
+ # Now, for each basic type, provide a basic `string` function.
+ # Later, more complex types will be added by plugins.
null: { string: -> "null" }
undefined: { string: -> "undefined" }
string: { string: $.identity }
@@ -861,7 +871,8 @@ class Bling extends Array
# __$.once(f)__ returns a new function that will only call
# _f_ **once**, or _n_ times if you pass the optional argument.
once: (f,n=1) -> f.n = n; (a...) -> (f.apply @,a) if f.n-- > 0
- # __$.bound(context,f,[args])__ returns a new function that forces this === context when called.
+ # __$.bound(context,f,[args])__ returns a new function that
+ # forces `this === context` when called.
bound: (t, f, args = []) ->
if $.is "function", f.bind
args.splice 0, 0, t
@@ -881,12 +892,12 @@ class Bling extends Array
# deep walk as labels).
$.plugin
provides: "trace"
- depends: "function"
+ depends: "function,type"
, ->
- $.type.extend null, trace: $.identity
$.type.extend
- object: { trace: (o, label, tracer) -> (o[k] = $.trace(o[k], "#{label}.#{k}", tracer) for k in Object.keys(o)); o }
- array: { trace: (o, label, tracer) -> (o[i] = $.trace(o[i], "#{label}[#{i}]", tracer) for i in [0...o.length]); o }
+ unknown: { trace: $.identity }
+ object: { trace: (o, label, tracer) -> (o[k] = $.trace(o[k], "#{label}.#{k}", tracer) for k in Object.keys(o)); o }
+ array: { trace: (o, label, tracer) -> (o[i] = $.trace(o[i], "#{label}[#{i}]", tracer) for i in [0...o.length]); o }
function:
trace: (f, label, tracer) ->
r = (a...) ->
@@ -907,12 +918,13 @@ class Bling extends Array
# `$.hash(o)` Reduces any thing to an integer hash code (not secure).
$.plugin
provides: "hash"
+ depends: "type"
, ->
- $.type.extend null, hash: (o) -> $.checksum $.toString(o)
$.type.extend
- object: { hash: (o) -> ($.hash(o[k]) for k of o) + $.hash(Object.keys(o)) }
- array: { hash: (o) -> ($.hash(i) for i in x).reduce (a,x) -> a+x }
- bool: { hash: (o) -> parseInt(1 if o) }
+ unknown: { hash: (o) -> $.checksum $.toString(o) }
+ object: { hash: (o) -> ($.hash(o[k]) for k of o) + $.hash(Object.keys(o)) }
+ array: { hash: (o) -> ($.hash(i) for i in x).reduce (a,x) -> a+x }
+ bool: { hash: (o) -> parseInt(1 if o) }
return {
$:
hash: (x) -> $.type.lookup(x).hash(x)
@@ -937,10 +949,9 @@ class Bling extends Array
if not func?
subscribers[e] = []
else
- subscribers[e] or= []
- i = subscribers[e].indexOf(func)
- if i > -1
- subscribers[e].splice(i,i)
+ a = (subscribers[e] or= [])
+ if (i = a.indexOf func) > -1
+ a.splice(i,i)
return {
$:
publish: publish
@@ -954,6 +965,7 @@ class Bling extends Array
# a function. Both are function decorators.
$.plugin
provides: "throttle"
+ depends: "core"
, ->
$:
throttle: (f,n=250,last=0) ->
@@ -972,7 +984,9 @@ class Bling extends Array
# -------------------
# The EventEmitter interface that Node.JS uses is much simpler (and faster) than the DOM event model.
# Example: `$.inherit new EventEmitter(), { myCode: () -> "..." }`
- $.plugin -> # EventEmitter
+ $.plugin
+ provides: "EventEmitter"
+ , ->
$: EventEmitter: class EventEmitter
constructor: -> @__event = {}
addListener: (e, h) -> (@__event[e] or= []).push(h); @emit('newListener', e, h)
@@ -986,354 +1000,358 @@ class Bling extends Array
if (window ? global).document?
- $.type.register "nodelist",
- match: (o) -> o? and $.isType "NodeList", o
- hash: (o) -> $($.hash(i) for i in x).sum()
- array: $.identity
- string: (o) -> "{nodelist:"+$(o).select('nodeName').join(",")+"}"
- node: -> $(@).toFragment()
- $.type.register "node",
- match: (o) -> o?.nodeType > 0
- hash: (o) -> $.checksum(o.nodeName) + $.hash(o.attributes) + $.checksum(o.innerHTML)
- string: (o) -> o.toString()
- node: $.identity
- $.type.register "fragment",
- match: (o) -> o?.nodeType is 11
- hash: (o) -> $($.hash(x) for x in o.childNodes).sum()
- string: (o) -> o.toString()
- node: $.identity
- $.type.register "html",
- match: (o) -> typeof o is "string" and (s=o.trimLeft())[0] == "<" and s[s.length-1] == ">"
- node: (o) -> $.type.lookup(h = Bling.HTML.parse(o)).node(h)
- array: (o,c) -> $.type.lookup(h = Bling.HTML.parse(o)).array(h,c)
- $.type.extend null, node: -> null
- $.type.extend
- bling: { node: -> $(@).toFragment() }
- string:
- node: -> $(@).toFragment()
- array: (o,c) -> c.querySelectorAll?(o)
- function: { node: -> $(@toString()).toFragment() }
- $.provide "document"
-
- $.plugin
- depends: "document,core"
- provides: "html"
- , -> # Html plugin
- toFrag = (a) ->
- if not a.parentNode?
- df = document.createDocumentFragment()
- df.appendChild(a)
- a
- before = (a,b) -> toFrag(a).parentNode.insertBefore b, a
- after = (a,b) -> toFrag(a).parentNode.insertBefore b, a.nextSibling
- toNode = (x) -> $.type.lookup(x).node(x)
- escaper = null
-
- # window.getComputedStyle is not a normal function
- # (it doesnt support .call() so we can't use it with .map())
- # so define something that does work properly for use in .css
- computeCSSProperty = (k) -> -> window.getComputedStyle(@, null).getPropertyValue(k)
+ # DOM Plugin
+ # ----------
+ $.plugin
+ depends: "function"
+ provides: "dom"
+ , ->
+ $.type.register "nodelist",
+ match: (o) -> o? and $.isType "NodeList", o
+ hash: (o) -> $($.hash(i) for i in x).sum()
+ array: $.identity
+ string: (o) -> "{nodelist:"+$(o).select('nodeName').join(",")+"}"
+ node: (o) -> $(o).toFragment()
+ $.type.register "node",
+ match: (o) -> o?.nodeType > 0
+ hash: (o) -> $.checksum(o.nodeName) + $.hash(o.attributes) + $.checksum(o.innerHTML)
+ string: (o) -> o.toString()
+ node: $.identity
+ $.type.register "fragment",
+ match: (o) -> o?.nodeType is 11
+ hash: (o) -> $($.hash(x) for x in o.childNodes).sum()
+ string: (o) -> o.toString()
+ node: $.identity
+ $.type.register "html",
+ match: (o) -> typeof o is "string" and (s=o.trimLeft())[0] == "<" and s[s.length-1] == ">"
+ node: (o) -> $.type.lookup(h = Bling.HTML.parse(o)).node(h)
+ array: (o,c) -> $.type.lookup(h = Bling.HTML.parse(o)).array(h,c)
+ $.type.extend
+ unknown: { node: -> null }
+ bling: { node: (o) -> o.toFragment() }
+ string:
+ node: (o) -> $(o).toFragment()
+ array: (o,c) -> c.querySelectorAll?(o)
+ function: { node: (o) -> $(o.toString()).toFragment() }
+
+ toFrag = (a) ->
+ if not a.parentNode?
+ df = document.createDocumentFragment()
+ df.appendChild(a)
+ a
+ before = (a,b) -> toFrag(a).parentNode.insertBefore b, a
+ after = (a,b) -> toFrag(a).parentNode.insertBefore b, a.nextSibling
+ toNode = (x) -> $.type.lookup(x).node(x)
+ escaper = null
+
+ # window.getComputedStyle is not a normal function
+ # (it doesnt support .call() so we can't use it with .map())
+ # so define something that does work properly for use in .css
+ computeCSSProperty = (k) -> -> window.getComputedStyle(@, null).getPropertyValue(k)
+
+ getOrSetRect = (p) -> (x) -> if x? then @css(p, x) else @rect().select(p)
+
+ return {
+ $:
+
+ # `$.HTML` provides methods similar to the global JSON
+ # object, for parsing from and to HTML.
+ HTML:
+ # Parse the html in string h into a node or fragment.
+ parse: (h) ->
+ # Put the html into a new div.
+ (node = document.createElement("div")).innerHTML = h
+ # If there's only one resulting child, return that Node.
+ if n = (childNodes = node.childNodes).length is 1
+ return node.removeChild(childNodes[0])
+ # Otherwise, copy all the div's children into a new
+ # fragment.
+ df = document.createDocumentFragment()
+ df.appendChild(node.removeChild(childNodes[0])) for i in [0...n]
+ df
+ # Convert a node or fragment to an HTML string.
+ stringify: (n) ->
+ switch $.type n
+ when "string","html" then n
+ when "node","fragment"
+ d = document.createElement "div"
+ d.appendChild (n = n.cloneNode true)
+ # Uses .innerHTML to render the HTML.
+ ret = d.innerHTML
+ d.removeChild n # break links to prevent leaks
+ ret
+ else "HTML.stringify of unknown type: " + $.type(n)
+ # Escape html characters in _h_, so "<" becomes "&lt;",
+ # etc.
+ escape: (h) ->
+ # Create a singleton div with a text node within it.
+ escaper or= $("<div>&nbsp;</div>").child(0)
+ # Insert _h_ using the text node's .data property,
+ # then get escaped html from the _parent's_ innerHTML.
+ ret = escaper.zap('data', h).select("parentNode.innerHTML").first()
+ # Clean up so content doesn't litter.
+ escaper.zap('data', '')
+ ret
+
+ # Get [or set] innerHTML for each node.
+ html: (h) ->
+ return switch $.type h
+ when "undefined","null" then @select 'innerHTML'
+ when "string" then @zap 'innerHTML', h
+ when "bling" then @html h.toFragment()
+ when "node"
+ @each -> # replace all our children with the new child
+ @replaceChild @childNodes[0], h
+ while @childNodes.length > 1
+ @removeChild @childNodes[1]
+
+ append: (x) -> # .append(/n/) - insert /n/ [or a clone] as the last child of each node
+ x = toNode(x) # parse, cast, do whatever it takes to get a Node or Fragment
+ @each -> @appendChild x.cloneNode true
+
+ appendTo: (x) -> # .appendTo(/n/) - each node [or fragment] will become the last child of x
+ clones = @map( -> @cloneNode true)
+ i = 0
+ $(x).each -> @appendChild clones[i++]
+ clones
+
+ prepend: (x) -> # .prepend(/n/) - insert n [or a clone] as the first child of each node
+ if x?
+ x = toNode(x)
+ @take(1).each ->
+ before @childNodes[0], x
+ @skip(1).each ->
+ before @childNodes[0], x.cloneNode(true)
+ @
- getOrSetRect = (p) -> (x) -> if x? then @css(p, x) else @rect().select(p)
+ prependTo: (x) -> # .prependTo(/n/) - each node [or a fragment] will become the first child of x
+ if x?
+ $(x).prepend(@)
+ @
- return {
- $:
+ before: (x) -> # .before(/x/) - insert content x before each node
+ if x?
+ x = toNode(x)
+ @take(1).each -> before @, x
+ @skip(1).each -> before @, x.cloneNode(true)
+ @
- # `$.HTML` provides methods similar to the global JSON
- # object, for parsing from and to HTML.
- HTML:
- # Parse the html in string h into a node or fragment.
- parse: (h) ->
- # Put the html into a new div.
- (node = document.createElement("div")).innerHTML = h
- # If there's only one resulting child, return that Node.
- if n = (childNodes = node.childNodes).length is 1
- return node.removeChild(childNodes[0])
- # Otherwise, copy all the div's children into a new
- # fragment.
- df = document.createDocumentFragment()
- df.appendChild(node.removeChild(childNodes[0])) for i in [0...n]
- df
- # Convert a node or fragment to an HTML string.
- stringify: (n) ->
- switch $.type n
- when "string","html" then n
- when "node","fragment"
- d = document.createElement "div"
- d.appendChild (n = n.cloneNode true)
- # Uses .innerHTML to render the HTML.
- ret = d.innerHTML
- d.removeChild n # break links to prevent leaks
- ret
- else "HTML.stringify of unknown type: " + $.type(n)
- # Escape html characters in _h_, so "<" becomes "&lt;",
- # etc.
- escape: (h) ->
- # Create a singleton div with a text node within it.
- escaper or= $("<div>&nbsp;</div>").child(0)
- # Insert _h_ using the text node's .data property,
- # then get escaped html from the _parent's_ innerHTML.
- ret = escaper.zap('data', h).select("parentNode.innerHTML").first()
- # Clean up so content doesn't litter.
- escaper.zap('data', '')
- ret
-
- # Get [or set] innerHTML for each node.
- html: (h) ->
- return switch $.type h
- when "undefined","null" then @select 'innerHTML'
- when "string" then @zap 'innerHTML', h
- when "bling" then @html h.toFragment()
- when "node"
- @each -> # replace all our children with the new child
- @replaceChild @childNodes[0], h
- while @childNodes.length > 1
- @removeChild @childNodes[1]
-
- append: (x) -> # .append(/n/) - insert /n/ [or a clone] as the last child of each node
- x = toNode(x) # parse, cast, do whatever it takes to get a Node or Fragment
- @each -> @appendChild x.cloneNode true
-
- appendTo: (x) -> # .appendTo(/n/) - each node [or a fragment] will become the last child of n
- $(x).append(@)
- try console.log "@.parentNode in appendTo:", @[0].parentNode, "should not be null"
- @
+ after: (x) -> # .after(/n/) - insert content n after each node
+ if x?
+ x = toNode(x)
+ @take(1).each -> after @, x
+ @skip(1).each -> after @, x.cloneNode(true)
+ @
- prepend: (x) -> # .prepend(/n/) - insert n [or a clone] as the first child of each node
- if x?
- x = toNode(x)
+ wrap: (parent) -> # .wrap(/p/) - p becomes the new .parentNode of each node
+ # all items of @ will become children of parent
+ # parent will take each child's position in the DOM
+ parent = toNode(parent)
+ if $.is("fragment", parent)
+ throw new Error("cannot wrap with a fragment")
+ @each (child) ->
+ switch $.type(child)
+ when "fragment"
+ parent.appendChild(child)
+ when "node"
+ p = child.parentNode
+ if not p
+ parent.appendChild(child)
+ else # swap out the DOM nodes using a placeholder element
+ marker = document.createElement("dummy")
+ # put a marker in the DOM, put removed node in new parent
+ parent.appendChild( p.replaceChild(marker, child) )
+ # replace marker with new parent
+ p.replaceChild(parent, marker)
+
+ unwrap: -> # .unwrap() - replace each node's parent with itself
+ @each ->
+ if @parentNode and @parentNode.parentNode
+ @parentNode.parentNode.replaceChild(@, @parentNode)
+ else if @parentNode
+ @parentNode.removeChild(@)
+
+ replace: (n) -> # .replace(/n/) - replace each node with n [or a clone]
+ n = toNode(n)
+ b = $()
+ j = 0
+ # first node gets the real n
@take(1).each ->
- before @childNodes[0], x
+ @parentNode?.replaceChild(n, @)
+ b[j++] = n
+ # the rest get clones of n
@skip(1).each ->
- before @childNodes[0], x.cloneNode(true)
- @
-
- prependTo: (x) -> # .prependTo(/n/) - each node [or a fragment] will become the first child of n
- if x?
- $(x).prepend(@)
- @
-
- before: (x) -> # .before(/x/) - insert content x before each node
- if x?
- x = toNode(x)
- @take(1).each -> before @, x
- @skip(1).each -> before @, x.cloneNode(true)
- @
-
- after: (x) -> # .after(/n/) - insert content n after each node
- if x?
- x = toNode(x)
- @take(1).each -> after @, x
- @skip(1).each -> after @, x.cloneNode(true)
- @
-
- wrap: (parent) -> # .wrap(/p/) - p becomes the new .parentNode of each node
- # all items of @ will become children of parent
- # parent will take each child's position in the DOM
- parent = toNode(parent)
- if $.is("fragment", parent)
- throw new Error("cannot wrap with a fragment")
- @each (child) ->
- switch $.type(child)
- when "fragment"
- parent.appendChild(child)
- when "node"
- p = child.parentNode
- if not p
- parent.appendChild(child)
- else # swap out the DOM nodes using a placeholder element
- marker = document.createElement("dummy")
- # put a marker in the DOM, put removed node in new parent
- parent.appendChild( p.replaceChild(marker, child) )
- # replace marker with new parent
- p.replaceChild(parent, marker)
-
- unwrap: -> # .unwrap() - replace each node's parent with itself
- @each ->
- if @parentNode and @parentNode.parentNode
- @parentNode.parentNode.replaceChild(@, @parentNode)
- else if @parentNode
- @parentNode.removeChild(@)
-
- replace: (n) -> # .replace(/n/) - replace each node with n [or a clone]
- n = toNode(n)
- b = $()
- j = 0
- # first node gets the real n
- @take(1).each ->
- @parentNode?.replaceChild(n, @)
- b[j++] = n
- # the rest get clones of n
- @skip(1).each ->
- c = n.cloneNode(true)
- @parentNode?.replaceChild(c, @)
- b[j++] = c
- # the set of inserted nodes
- b
-
- attr: (a,v) -> # .attr(a, [v]) - get [or set] an /a/ttribute [/v/alue]
- switch v
- when undefined
- return @select("getAttribute").call(a, v)
- when null
- return @select("removeAttribute").call(a, v)
- else
- @select("setAttribute").call(a, v)
+ c = n.cloneNode(true)
+ @parentNode?.replaceChild(c, @)
+ b[j++] = c
+ # the set of inserted nodes
+ b
+
+ attr: (a,v) -> # .attr(a, [v]) - get [or set] an /a/ttribute [/v/alue]
+ switch v
+ when undefined
+ return @select("getAttribute").call(a, v)
+ when null
+ return @select("removeAttribute").call(a, v)
+ else
+ @select("setAttribute").call(a, v)
+ return @
+
+ data: (k, v) ->
+ k = "data-#{$.dashize(k)}"
+ @attr(k, v)
+
+ addClass: (x) -> # .addClass(/x/) - add x to each node's .className
+ @removeClass(x).each ->
+ c = @className.split(" ").filter (y) ->
+ y isnt ""
+ c.push(x) # since we dont know the len, its still faster to push, rather than insert at len()
+ @className = c.join " "
+
+ removeClass: (x) -> # .removeClass(/x/) - remove class x from each node's .className
+ notx = (y)-> y != x
+ @each ->
+ c = @className?.split(" ").filter(notx).join(" ")
+ if c.length is 0
+ @removeAttribute('class')
+
+ toggleClass: (x) -> # .toggleClass(/x/) - add, or remove if present, class x from each node
+ notx = (y) -> y isnt x
+ @each ->
+ cls = @className.split(" ")
+ filter = $.not $.isEmpty
+ if( cls.indexOf(x) > -1 )
+ filter = $.and notx, filter
+ else
+ cls.push(x)
+ c = cls.filter(filter).join(" ")
+ @className = c
+ if c.length is 0
+ @removeAttribute('class')
+
+ hasClass: (x) -> # .hasClass(/x/) - true/false for each node: whether .className contains x
+ @select('className.split').call(" ").select('indexOf').call(x).map (x) -> x > -1
+
+ text: (t) -> # .text([t]) - get [or set] each node's .textContent
+ return @zap('textContent', t) if t?
+ return @select('textContent')
+
+ val: (v) -> # .val([v]) - get [or set] each node's .value
+ return @zap('value', v) if v?
+ return @select('value')
+
+ # Get [or set] css properties.
+ css: (k,v) ->
+ # If we are doing assignment.
+ if v? or $.is "object", k
+ # Use a bound-method to do the assignment for us.
+ setter = @select 'style.setProperty'
+ # If you give an object as a key, then use every k:v pair.
+ if $.is "object", k then setter.call i, k[i], "" for i of k
+ # So, the key is simple, and if the value is a string,
+ # just do simple assignment (using setProperty).
+ else if $.is "string", v then setter.call k, v, ""
+ # If the value was actually an array of values, then
+ # stripe the values across each item.
+ else if $.is "array", v
+ setter[i%nn] k, v[i%n], "" for i in [0...n = Math.max v.length, nn = setter.len()]
return @
-
- data: (k, v) ->
- k = "data-#{$.dashize(k)}"
- @attr(k, v)
-
- addClass: (x) -> # .addClass(/x/) - add x to each node's .className
- @removeClass(x).each ->
- c = @className.split(" ").filter (y) ->
- y isnt ""
- c.push(x) # since we dont know the len, its still faster to push, rather than insert at len()
- @className = c.join " "
-
- removeClass: (x) -> # .removeClass(/x/) - remove class x from each node's .className
- notx = (y)-> y != x
- @each ->
- c = @className?.split(" ").filter(notx).join(" ")
- if c.length is 0
- @removeAttribute('class')
-
- toggleClass: (x) -> # .toggleClass(/x/) - add, or remove if present, class x from each node
- notx = (y) -> y isnt x
- @each ->
- cls = @className.split(" ")
- filter = $.not $.isEmpty
- if( cls.indexOf(x) > -1 )
- filter = $.and notx, filter
+ # Else, we are reading CSS properties.
else
- cls.push(x)
- c = cls.filter(filter).join(" ")
- @className = c
- if c.length is 0
- @removeAttribute('class')
-
- hasClass: (x) -> # .hasClass(/x/) - true/false for each node: whether .className contains x
- @select('className.split').call(" ").select('indexOf').call(x).map (x) -> x > -1
-
- text: (t) -> # .text([t]) - get [or set] each node's .textContent
- return @zap('textContent', t) if t?
- return @select('textContent')
-
- val: (v) -> # .val([v]) - get [or set] each node's .value
- return @zap('value', v) if v?
- return @select('value')
-
- # Get [or set] css properties.
- css: (k,v) ->
- # If we are doing assignment.
- if v? or $.is "object", k
- # Use a bound-method to do the assignment for us.
- setter = @select 'style.setProperty'
- # If you give an object as a key, then use every k:v pair.
- if $.is "object", k then setter.call i, k[i], "" for i of k
- # So, the key is simple, and if the value is a string,
- # just do simple assignment (using setProperty).
- else if $.is "string", v then setter.call k, v, ""
- # If the value was actually an array of values, then
- # stripe the values across each item.
- else if $.is "array", v
- setter[i%nn] k, v[i%n], "" for i in [0...n = Math.max v.length, nn = setter.len()]
- return @
- # Else, we are reading CSS properties.
- else
- # So, collect the full computed values.
- cv = @map computeCSSProperty(k)
- # Then, collect the values specified directly on the node.
- ov = @select('style').select k
- # Weave and fold them so that object values override
- # computed values.
- ov.weave(cv).fold (x,y) -> x or y
-
- # Set css properties by injecting a style element in the the
- # head. If _k_ is an object of k:v pairs, then no second argument is needed.
- defaultCss: (k, v) ->
- # @selector need not match any nodes at the time of the call.
- sel = @selector
- style = ""
- if $.is "string", k
- if $.is "string", v
- style += "#{sel} { #{k}: #{v} } "
- else throw Error("defaultCss requires a value with a string key")
- else if $.is "object", k
- style += "#{sel} { " +
- "#{i}: #{k[i]}; " for i of k +
- "} "
- $("<style></style>").text(style).appendTo("head")
- @
+ # So, collect the full computed values.
+ cv = @map computeCSSProperty(k)
+ # Then, collect the values specified directly on the node.
+ ov = @select('style').select k
+ # Weave and fold them so that object values override
+ # computed values.
+ ov.weave(cv).fold (x,y) -> x or y
+
+ # Set css properties by injecting a style element in the the
+ # head. If _k_ is an object of k:v pairs, then no second argument is needed.
+ defaultCss: (k, v) ->
+ # @selector need not match any nodes at the time of the call.
+ sel = @selector
+ style = ""
+ if $.is "string", k
+ if $.is "string", v
+ style += "#{sel} { #{k}: #{v} } "
+ else throw Error("defaultCss requires a value with a string key")
+ else if $.is "object", k
+ style += "#{sel} { " +
+ "#{i}: #{k[i]}; " for i of k +
+ "} "
+ $("<style></style>").text(style).appendTo("head")
+ @
- # Get a bounding-box for each item.
- rect: -> @select('getBoundingClientRect').call()
+ # Get a bounding-box for each item.
+ rect: -> @select('getBoundingClientRect').call()
- # Get [or set] each item's width.
- width: getOrSetRect("width")
+ # Get [or set] each item's width.
+ width: getOrSetRect("width")
- # Get [or set] each item's height.
- height: getOrSetRect("height")
+ # Get [or set] each item's height.
+ height: getOrSetRect("height")
- # Get [or set] each item's top.
- top: getOrSetRect("top")
+ # Get [or set] each item's top.
+ top: getOrSetRect("top")
- # Get [or set] each item's left.
- left: getOrSetRect("left")
+ # Get [or set] each item's left.
+ left: getOrSetRect("left")
- # Get [or set] each item's bottom.
- bottom: getOrSetRect("bottom")
+ # Get [or set] each item's bottom.
+ bottom: getOrSetRect("bottom")
- # Get [or set] each item's right.
- right: getOrSetRect("right")
+ # Get [or set] each item's right.
+ right: getOrSetRect("right")
- # Get [or set] each item's position.
- position: (left, top) ->
- switch true
- # If called with no arguments, just return the position.
- when not left? then @rect()
- # If called with only one argument, only set "left".
- when not top? then @css("left", $.px(left))
- # If called with both arguments, set "top" and "left".
- else @css({top: $.px(top), left: $.px(left)})
-
- # Adjust the document's scroll position so the first node in
- # _this_ is centered in the viewport.
- scrollToCenter: ->
- document.body.scrollTop = @[0].offsetTop - (window.innerHeight / 2)
- @
+ # Get [or set] each item's position.
+ position: (left, top) ->
+ switch true
+ # If called with no arguments, just return the position.
+ when not left? then @rect()
+ # If called with only one argument, only set "left".
+ when not top? then @css("left", $.px(left))
+ # If called with both arguments, set "top" and "left".
+ else @css({top: $.px(top), left: $.px(left)})
- # Get the _n-th_ child from each node in _this_.
- child: (n) -> @select('childNodes').map -> @[ if n < 0 then (n+@length) else n ]
+ # Adjust the document's scroll position so the first node in
+ # _this_ is centered in the viewport.
+ scrollToCenter: ->
+ document.body.scrollTop = @[0].offsetTop - (window.innerHeight / 2)
+ @
- parents: -> @map -> p = @; $( p while p = p?.parentNode ) # .parents() - collects the full ancestry up to the owner
+ # Get the _n-th_ child from each node in _this_.
+ child: (n) -> @select('childNodes').map -> @[ if n < 0 then (n+@length) else n ]
- prev: -> @map -> p = @; $( p while p = p?.previousSibling ) # .prev() - collects the chain of .previousSibling nodes
+ parents: -> @map -> p = @; $( p while p = p?.parentNode ) # .parents() - collects the full ancestry up to the owner
- next: -> @map -> p = @; $( p while p = p?.nextSibling ) # .next() - collect the chain of .nextSibling nodes
+ prev: -> @map -> p = @; $( p while p = p?.previousSibling ) # .prev() - collects the chain of .previousSibling nodes
- remove: -> @each -> @parentNode?.removeChild(@) # .remove() - removes each node in _this_ from the DOM
+ next: -> @map -> p = @; $( p while p = p?.nextSibling ) # .next() - collect the chain of .nextSibling nodes
- find: (css) -> # .find(/css/) - collect nodes matching /css/
- @filter("*") # limit to only DOM nodes
- .map( -> $(css, @) )
- .flatten()
+ remove: -> @each -> @parentNode?.removeChild(@) # .remove() - removes each node in _this_ from the DOM
- clone: (deep=true) -> @map -> (@cloneNode deep) if $.is "node", @ # .clone(deep=true) - copies a set of DOM nodes
+ find: (css) -> # .find(/css/) - collect nodes matching /css/
+ @filter("*") # limit to only DOM nodes
+ .map( -> $(css, @) )
+ .flatten()
- toFragment: ->
- if @length > 1
- df = document.createDocumentFragment()
- @map(toNode).map $.bound df, df.appendChild
- return df
- return toNode(@[0])
- }
+ clone: (deep=true) -> @map -> (@cloneNode deep) if $.is "node", @ # .clone(deep=true) - copies a set of DOM nodes
+
+ toFragment: ->
+ if @length > 1
+ df = document.createDocumentFragment()
+ @map(toNode).map $.bound df, df.appendChild
+ return df
+ return toNode(@[0])
+ }
+ # Transform plugin
+ # ----------------
+ # For accelerated animations.
$.plugin
- provides: "transform"
- depends: "math,html"
- , -> # Transform plugin, for accelerated animations
+ depends: "dom"
+ , ->
COMMASEP = ", "
speeds = # constant speed names
"slow": 700
@@ -1371,12 +1389,14 @@ class Bling extends Array
return {
$:
- duration: (speed) -> # $.duration(/s/) - given a speed description (string|number), return a number in milliseconds
- speeds[speed] ? parseFloat speed
+ # $.duration(/s/) - given a speed description (string|number), return a number in milliseconds
+ duration: (speed) ->
+ d = speeds[speed]
+ return d if d?
+ return parseFloat speed
- # like jquery's animate(), but using only webkit-transition/transform
+ # .transform(css, [/speed/], [/callback/]) - animate css properties on each node
transform: (end_css, speed, easing, callback) ->
- # .transform(css, [/speed/], [/callback/]) - animate css properties on each node
# animate css properties over a duration
# accelerated: scale, translate, rotate, scale3d,
# ... translateX, translateY, translateZ, translate3d,
@@ -1387,19 +1407,16 @@ class Bling extends Array
if $.is("function",speed)
callback = speed
- speed = null
- easing = null
+ speed = easing = null
else if $.is("function",easing)
callback = easing
easing = null
- if not speed?
- speed = "normal"
+ speed ?= "normal"
easing or= "ease"
# duration is always in milliseconds
duration = $.duration(speed) + "ms"
props = []
- p = 0 # insert marker for props
- # what to send to the -webkit-transform
+ # `trans` is what will be assigned to -webkit-transform
trans = ""
# real css values to be set (end_css without the transform values)
css = {}
@@ -1408,38 +1425,33 @@ class Bling extends Array
if accel_props_re.test(i)
ii = end_css[i]
if ii.join
- ii = $(ii).px().join(COMMASEP)
+ ii = $(ii).px().join COMMASEP
else if ii.toString
ii = ii.toString()
trans += " " + i + "(" + ii + ")"
- else # stick real css values in the css dict
- css[i] = end_css[i]
+ # stick real css values in the css dict
+ else css[i] = end_css[i]
# make a list of the properties to be modified
- for i of css
- props[p++] = i
+ (props.push i) for i of css
# and include -webkit-transform if we have transform values to set
if trans
- props[p++] = transformProperty
+ props.push transformProperty
# sets a list of properties to apply a duration to
- css[transitionProperty] = props.join(COMMASEP)
+ css[transitionProperty] = props.join COMMASEP
# apply the same duration to each property
- css[transitionDuration] =
- props.map( -> duration)
- .join(COMMASEP)
+ css[transitionDuration] = props.map(-> duration).join COMMASEP
# apply an easing function to each property
- css[transitionTiming] =
- props.map( -> easing)
- .join(COMMASEP)
+ css[transitionTiming] = props.map(-> easing).join COMMASEP
# apply the transformation
- if( trans )
+ if trans
css[transformProperty] = trans
# apply the css to the actual node
- @css(css)
+ @css css
# queue the callback to be executed at the end of the animation
# WARNING: NOT EXACT!
- @delay(duration, callback)
+ @delay duration, callback
hide: (callback) -> # .hide() - each node gets display:none
@each ->
@@ -1448,16 +1460,16 @@ class Bling extends Array
if @style.display is not "none"
@_display = @syle.display
@style.display = "none"
- .trigger("hide")
- .delay(updateDelay, callback)
+ .trigger "hide"
+ .delay updateDelay, callback
show: (callback) -> # .show() - show each node
@each ->
if @style
@style.display = @_display
delete @_display
- .trigger("show")
- .delay(updateDelay, callback)
+ .trigger "show"
+ .delay updateDelay, callback
toggle: (callback) -> # .toggle() - show each hidden node, hide each visible one
@weave(@css("display"))
@@ -1465,50 +1477,53 @@ class Bling extends Array
if display is "none"
node.style.display = node._display or ""
delete node._display
- $(node).trigger("show")
+ $(node).trigger "show"
else
node._display = display
node.style.display = "none"
- $(node).trigger("hide")
+ $(node).trigger "hide"
node
.delay(updateDelay, callback)
fadeIn: (speed, callback) -> # .fadeIn() - fade each node to opacity 1.0
- @css('opacity','0.0')
+ @.css('opacity','0.0')
.show ->
- @transform
+ @transform {
opacity:"1.0",
translate3d: [0,0,0]
- , speed, callback
+ }, speed, callback
fadeOut: (speed, callback, x = 0.0, y = 0.0) -> # .fadeOut() - fade each node to opacity:0.0
- @transform
+ @transform {
opacity:"0.0",
translate3d:[x,y,0.0]
- , speed, -> @hide(callback)
- fadeLeft: (speed, callback) -> @fadeOut(speed, callback, "-"+@width().first(), 0.0)
- fadeRight: (speed, callback) -> @fadeOut(speed, callback, @width().first(), 0.0)
- fadeUp: (speed, callback) -> @fadeOut(speed, callback, 0.0, "-"+@height().first())
- fadeDown: (speed, callback) -> @fadeOut(speed, callback, 0.0, @height().first())
+ }, speed, -> @hide(callback)
+ fadeLeft: (speed, callback) -> @fadeOut speed, callback, "-"+@width().first(), 0.0
+ fadeRight: (speed, callback) -> @fadeOut speed, callback, @width().first(), 0.0
+ fadeUp: (speed, callback) -> @fadeOut speed, callback, 0.0, "-"+@height().first()
+ fadeDown: (speed, callback) -> @fadeOut speed, callback, 0.0, @height().first()
}
+ # HTTP Plugin
+ # -----------
+ # Things like `.ajax()`, `.get()`, `$.post()`.
$.plugin
- depends: "function"
- provides: "http"
- , -> # HTTP Request plugin: provides wrappers for making http requests
+ depends: "dom"
+ , ->
formencode = (obj) -> # create &foo=bar strings from object properties
o = JSON.parse(JSON.stringify(obj)) # quickly remove all non-stringable items
- ("#{i}=#{escape o[i]}" for i of o).join("&")
+ ("#{i}=#{escape o[i]}" for i of o).join "&"
$.type.register "http",
match: (o) -> $.isType 'XMLHttpRequest', o
array: (o) -> [o]
return {
- $: # globals
- http: (url, opts = {}) -> # $.http(/url/, [/opts/]) - fetch /url/ using HTTP (method in /opts/)
+ $:
+ # $.http(/url/, [/opts/]) - fetch /url/ using HTTP (method in /opts/)
+ http: (url, opts = {}) ->
xhr = new XMLHttpRequest()
if $.is("function",opts)
- opts = {success: $.bound(xhr, opts)}
+ opts = success: $.bound(xhr, opts)
opts = $.extend {
method: "GET"
data: null
@@ -1544,23 +1559,28 @@ class Bling extends Array
xhr.send opts.data
return $(xhr)
- post: (url, opts = {}) -> # $.post(/url/, [/opts/]) - fetch /url/ with a POST request
- if $.is "function", opts
+ # $.post(/url/, [/opts/]) - fetch /url/ with a POST request
+ post: (url, opts = {}) ->
+ if $.is("function",opts)
opts = success: opts
opts.method = "POST"
$.http(url, opts)
- get: (url, opts = {}) -> # $.get(/url/, [/opts/]) - fetch /url/ with a GET request
- if $.is "function", opts
+ # $.get(/url/, [/opts/]) - fetch /url/ with a GET request
+ get: (url, opts = {}) ->
+ if( $.is("function",opts) )
opts = success: opts
opts.method = "GET"
$.http(url, opts)
}
+ # Events plugin
+ # -------------
+ # Things like `.bind()`, `.trigger()`, etc.
$.plugin
- depends: "html"
+ depends: "dom,function,core"
provides: "event"
- , -> # Events plugin
+ , ->
EVENTSEP_RE = /,* +/
events = ['mousemove','mousedown','mouseup','mouseover','mouseout','blur','focus',
'load','unload','reset','submit','keyup','keydown','change',
@@ -1587,11 +1607,11 @@ class Bling extends Array
delete c[f]
# detect and fire the document.ready event
- triggerReady = Function.Once ->
+ triggerReady = $.once ->
$(document).trigger("ready").unbind("ready")
document.removeEventListener?("DOMContentLoaded", triggerReady, false)
window.removeEventListener?("load", triggerReady, false)
- bindReady = Function.Once ->
+ bindReady = $.once ->
document.addEventListener?("DOMContentLoaded", triggerReady, false)
window.addEventListener?("load", triggerReady, false)
bindReady()
@@ -1756,8 +1776,9 @@ class Bling extends Array
return ret
$.plugin
+ depends: "dom"
provides: "lazy"
- , -> # LazyLoader plugin
+ , ->
lazy_load = (elementName, props) ->
$("head").append $.extend document.createElement(elementName), props
$:
@@ -1767,6 +1788,5 @@ class Bling extends Array
lazy_load "link", { href: src, rel: "stylesheet" }
-
)(Bling)
# vim: ft=coffee sw=2 ts=2
View
30 tests/bling.coffee
@@ -134,18 +134,20 @@ testGroup("Core",
{a:[{b:6}]},
{a:[{b:9}]}
]).select("a.0.b"), [3,6,9])
+ select3: -> assertArrayEqual($([
+ {a:{b:{c:4}}},
+ {a:{b:{c:5}}},
+ {a:{b:{c:6}}}
+ ]).select("a.b.c"), [4,5,6])
zap: -> assertArrayEqual($([ {id:1}, {id:2}, {id:3} ]).zap('id', 13).select('id'), [13,13,13])
- #zapf: -> assertArrayEqual($([ {id:1}, {id:2}, {id:3} ]).zap('id', () -> @ * 2).select('id'), [2,4,6])
- #zapf2: -> assertArrayEqual($([ {sub:{id:1}}, {sub:{id:2}}, {sub:{id:3}} ]).zap('sub.id', () -> @ * 2).select('sub.id'), [2,4,6])
- take1: -> assertArrayEqual($([1,2,3,4]).take(-2), [3,4])
- take2: -> assertArrayEqual($([1,2,3,4]).take(-1), [4])
+ zapf: -> assertArrayEqual($([ {id:1}, {id:2}, {id:3} ]).zap('id', () -> @ * 2).select('id'), [2,4,6])
+ zapf2: -> assertArrayEqual( $([ {sub:{id:1}}, {sub:{id:2}}, {sub:{id:3}} ]).zap('sub.id', -> @*2).select('sub.id'), [2,4,6])
take3: -> assertArrayEqual($([1,2,3,4]).take(0), [])
take4: -> assertArrayEqual($([1,2,3,4]).take(1), [1])
take5: -> assertArrayEqual($([1,2,3,4]).take(2), [1,2])
take6: -> assertArrayEqual($([1,2,3,4]).take(3), [1,2,3])
take7: -> assertArrayEqual($([1,2,3,4]).take(4), [1,2,3,4])
take8: -> assertArrayEqual($([1,2,3,4]).take(5), [1,2,3,4])
- skip1: -> assertArrayEqual($([1,2,3,4]).skip(-1), [1,2,3,4])
skip2: -> assertArrayEqual($([1,2,3,4]).skip(0), [1,2,3,4])
skip3: -> assertArrayEqual($([1,2,3,4]).skip(1), [2,3,4])
skip4: -> assertArrayEqual($([1,2,3,4]).skip(2), [3,4])
@@ -207,19 +209,27 @@ testGroup("HTML",
t.zap('data', '<p>')
assertEqual( d.select('innerHTML').first(), '&lt;p&gt;' )
escape: -> assertEqual($.HTML.escape("<p>"), "&lt;p&gt;")
- dashName1: -> assertEqual(String.Dashize("fooBar"), "foo-bar")
- dashName2: -> assertEqual(String.Dashize("FooBar"), "-foo-bar")
+ dashName1: -> assertEqual($.dashize("fooBar"), "foo-bar")
+ dashName2: -> assertEqual($.dashize("FooBar"), "-foo-bar")
html: -> assertEqual($("tr").html().first(), "<td>1,1</td><td>1,2</td>")
append: ->
try
assertEqual($("tr td.d").append("<span>Hi</span>").html().first(), "3,2<span>Hi</span>")
finally
$("tr td.d span").remove()
- appendTo:->
+ appendTo1:-> assertEqual($("<span>Hi</span>").toString(), "$([<span>Hi</span>])")
+ appendTo2:->
try
- assertEqual($("<span>Hi</span>").toString(), "$([<span>Hi</span>])")
assertEqual($("<span>Hi</span>").appendTo("tr td.d").toString(), "$([<span>Hi</span>])")
- assertEqual($("<span>Hi</span>").appendTo("tr td.d").select('parentNode').toString(), "$([<td class='d'><span>Hi</span></td>])")
+ finally
+ $("tr td.d span").remove()
+ appendTo3:->
+ try
+ assertEqual($("<span>Hi</span>").appendTo("tr td.d").select('parentNode').toString(), '$([<td class="d">3,2<span>Hi</span></td>])')
+ finally
+ $("tr td.d span").remove()
+ appendTo4:->
+ try
assertEqual($("<span>Hi</span>").appendTo("tr td.d").select('parentNode').html().first(), "3,2<span>Hi</span>")
finally
$("tr td.d span").remove()
2  tests/domjs
@@ -1 +1 @@
-Subproject commit aaf901a6ad9536d713364df5c3303d6743879ede
+Subproject commit 6c1329ab70d7e98ec8a352f66adc4efa80589e17

No commit comments for this range

Something went wrong with that request. Please try again.