Skip to content
Toggle navigation
Toggle navigation
This project
Loading...
Sign in
brainfood
/
rivets
Go to a project
Toggle navigation
Toggle navigation pinning
Projects
Groups
Snippets
Help
Project
Activity
Repository
Graphs
Network
Create a new issue
Commits
Issue Boards
Files
Commits
Network
Compare
Branches
Tags
962107e9
authored
2012-07-30 17:20:09 -0700
by
Michael Richards
Browse Files
Options
Browse Files
Tag
Download
Plain Diff
Merge pull request #39 from mikeric/adapter-bypass
Additional syntax to bypass the adapter
2 parents
982e2361
15f661c9
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
97 additions
and
46 deletions
lib/rivets.js
lib/rivets.min.js
spec/rivets/binding.js
src/rivets.coffee
lib/rivets.js
View file @
962107e
...
...
@@ -3,7 +3,7 @@
// author: Michael Richards
// license: MIT
(
function
()
{
var
Rivets
,
attributeBinding
,
bi
directionals
,
bi
ndEvent
,
eventBinding
,
getInputValue
,
rivets
,
unbindEvent
,
var
Rivets
,
attributeBinding
,
bindEvent
,
eventBinding
,
getInputValue
,
rivets
,
unbindEvent
,
__bind
=
function
(
fn
,
me
){
return
function
(){
return
fn
.
apply
(
me
,
arguments
);
};
},
__slice
=
[].
slice
,
__indexOf
=
[].
indexOf
||
function
(
item
)
{
for
(
var
i
=
0
,
l
=
this
.
length
;
i
<
l
;
i
++
)
{
if
(
i
in
this
&&
this
[
i
]
===
item
)
return
i
;
}
return
-
1
;
};
...
...
@@ -18,13 +18,12 @@
Rivets
.
Binding
=
(
function
()
{
function
Binding
(
el
,
type
,
bindType
,
model
,
keypath
,
formatter
s
)
{
function
Binding
(
el
,
type
,
model
,
keypath
,
option
s
)
{
this
.
el
=
el
;
this
.
type
=
type
;
this
.
bindType
=
bindType
;
this
.
model
=
model
;
this
.
keypath
=
keypath
;
this
.
formatters
=
formatters
!=
null
?
formatters
:
[]
;
this
.
options
=
options
!=
null
?
options
:
{}
;
this
.
unbind
=
__bind
(
this
.
unbind
,
this
);
this
.
publish
=
__bind
(
this
.
publish
,
this
);
...
...
@@ -35,41 +34,52 @@
this
.
formattedValue
=
__bind
(
this
.
formattedValue
,
this
);
if
(
this
.
bindType
===
"event"
)
{
if
(
this
.
options
.
special
===
"event"
)
{
this
.
routine
=
eventBinding
(
this
.
type
);
}
else
{
this
.
routine
=
Rivets
.
routines
[
this
.
type
]
||
attributeBinding
(
this
.
type
);
}
this
.
formatters
=
this
.
options
.
formatters
||
[];
}
Binding
.
prototype
.
bidirectionals
=
[
'value'
,
'checked'
,
'unchecked'
];
Binding
.
prototype
.
formattedValue
=
function
(
value
)
{
var
args
,
formatter
,
id
,
_i
,
_len
,
_ref
,
_ref1
;
var
args
,
formatter
,
id
,
_i
,
_len
,
_ref
,
_ref1
,
_ref2
;
_ref
=
this
.
formatters
;
for
(
_i
=
0
,
_len
=
_ref
.
length
;
_i
<
_len
;
_i
++
)
{
formatter
=
_ref
[
_i
];
args
=
formatter
.
split
(
/
\s
+/
);
id
=
args
.
shift
();
value
=
(
_ref1
=
Rivets
.
config
.
formatters
)[
id
].
apply
(
_ref1
,
[
value
].
concat
(
__slice
.
call
(
args
)));
value
=
Rivets
.
config
.
formatters
&&
Rivets
.
config
.
formatters
[
id
]
?
(
_ref1
=
Rivets
.
config
.
formatters
)[
id
].
apply
(
_ref1
,
[
value
].
concat
(
__slice
.
call
(
args
)))
:
(
_ref2
=
this
.
model
)[
id
].
apply
(
_ref2
,
[
value
].
concat
(
__slice
.
call
(
args
)));
}
return
value
;
};
Binding
.
prototype
.
set
=
function
(
value
)
{
value
=
this
.
formattedValue
(
value
);
if
(
this
.
bindType
===
"event"
)
{
if
(
this
.
options
.
special
===
"event"
)
{
this
.
routine
(
this
.
el
,
value
,
this
.
currentListener
);
return
this
.
currentListener
=
value
;
}
else
{
if
(
value
instanceof
Function
)
{
value
=
value
();
}
return
this
.
routine
(
this
.
el
,
value
);
}
};
Binding
.
prototype
.
bind
=
function
()
{
Rivets
.
config
.
adapter
.
subscribe
(
this
.
model
,
this
.
keypath
,
this
.
set
);
if
(
Rivets
.
config
.
preloadData
)
{
this
.
set
(
Rivets
.
config
.
adapter
.
read
(
this
.
model
,
this
.
keypath
));
var
_ref
;
if
(
this
.
options
.
bypass
)
{
this
.
set
(
this
.
model
[
this
.
keypath
]);
}
else
{
Rivets
.
config
.
adapter
.
subscribe
(
this
.
model
,
this
.
keypath
,
this
.
set
);
if
(
Rivets
.
config
.
preloadData
)
{
this
.
set
(
Rivets
.
config
.
adapter
.
read
(
this
.
model
,
this
.
keypath
));
}
}
if
(
this
.
bindType
===
"bidirectional"
)
{
if
(
_ref
=
this
.
type
,
__indexOf
.
call
(
this
.
bidirectionals
,
_ref
)
>=
0
)
{
return
bindEvent
(
this
.
el
,
'change'
,
this
.
publish
);
}
};
...
...
@@ -81,8 +91,9 @@
};
Binding
.
prototype
.
unbind
=
function
()
{
var
_ref
;
Rivets
.
config
.
adapter
.
unsubscribe
(
this
.
model
,
this
.
keypath
,
this
.
set
);
if
(
this
.
bindType
===
"bidirectional"
)
{
if
(
_ref
=
this
.
type
,
__indexOf
.
call
(
this
.
bidirectionals
,
_ref
)
>=
0
)
{
return
this
.
el
.
removeEventListener
(
'change'
,
this
.
publish
);
}
};
...
...
@@ -127,13 +138,13 @@
bindingRegExp
=
this
.
bindingRegExp
();
eventRegExp
=
/^on-/
;
parseNode
=
function
(
node
)
{
var
attribute
,
bindType
,
keypath
,
model
,
path
,
pipe
,
pipes
,
type
,
_i
,
_len
,
_ref
,
_results
;
var
attribute
,
keypath
,
model
,
options
,
path
,
pipe
,
pipes
,
type
,
_i
,
_len
,
_ref
,
_results
;
_ref
=
node
.
attributes
;
_results
=
[];
for
(
_i
=
0
,
_len
=
_ref
.
length
;
_i
<
_len
;
_i
++
)
{
attribute
=
_ref
[
_i
];
if
(
bindingRegExp
.
test
(
attribute
.
name
))
{
bindType
=
"attribute"
;
options
=
{}
;
type
=
attribute
.
name
.
replace
(
bindingRegExp
,
''
);
pipes
=
(
function
()
{
var
_j
,
_len1
,
_ref1
,
_results1
;
...
...
@@ -145,16 +156,16 @@
}
return
_results1
;
})();
path
=
pipes
.
shift
().
split
(
'.'
);
path
=
pipes
.
shift
().
split
(
/
(\.
|:
)
/
);
options
.
formatters
=
pipes
;
model
=
_this
.
models
[
path
.
shift
()];
keypath
=
path
.
join
(
'.'
);
options
.
bypass
=
path
.
shift
()
===
':'
;
keypath
=
path
.
join
();
if
(
eventRegExp
.
test
(
type
))
{
type
=
type
.
replace
(
eventRegExp
,
''
);
bindType
=
"event"
;
}
else
if
(
__indexOf
.
call
(
bidirectionals
,
type
)
>=
0
)
{
bindType
=
"bidirectional"
;
options
.
special
=
"event"
;
}
_results
.
push
(
_this
.
bindings
.
push
(
new
Rivets
.
Binding
(
node
,
type
,
bindType
,
model
,
keypath
,
pipe
s
)));
_results
.
push
(
_this
.
bindings
.
push
(
new
Rivets
.
Binding
(
node
,
type
,
model
,
keypath
,
option
s
)));
}
else
{
_results
.
push
(
void
0
);
}
...
...
@@ -256,8 +267,6 @@
};
};
bidirectionals
=
[
'value'
,
'checked'
,
'unchecked'
];
Rivets
.
routines
=
{
enabled
:
function
(
el
,
value
)
{
return
el
.
disabled
=
!
value
;
...
...
lib/rivets.min.js
View file @
962107e
...
...
@@ -2,4 +2,4 @@
// version: 0.2.5
// author: Michael Richards
// license: MIT
(
function
(){
var
a
,
b
,
c
,
d
,
e
,
f
,
g
,
h
,
i
=
function
(
a
,
b
){
return
function
(){
return
a
.
apply
(
b
,
arguments
)}},
j
=
[].
slice
,
k
=
[].
indexOf
||
function
(
a
){
for
(
var
b
=
0
,
c
=
this
.
length
;
b
<
c
;
b
++
)
if
(
b
in
this
&&
this
[
b
]
===
a
)
return
b
;
return
-
1
};
a
=
{},
String
.
prototype
.
trim
||
(
String
.
prototype
.
trim
=
function
(){
return
this
.
replace
(
/^
\s
+|
\s
+$/g
,
""
)}),
a
.
Binding
=
function
(){
function
c
(
c
,
d
,
f
,
g
,
h
,
j
){
this
.
el
=
c
,
this
.
type
=
d
,
this
.
bindType
=
f
,
this
.
model
=
g
,
this
.
keypath
=
h
,
this
.
formatters
=
j
!=
null
?
j
:[],
this
.
unbind
=
i
(
this
.
unbind
,
this
),
this
.
publish
=
i
(
this
.
publish
,
this
),
this
.
bind
=
i
(
this
.
bind
,
this
),
this
.
set
=
i
(
this
.
set
,
this
),
this
.
formattedValue
=
i
(
this
.
formattedValue
,
this
),
this
.
bindType
===
"event"
?
this
.
routine
=
e
(
this
.
type
):
this
.
routine
=
a
.
routines
[
this
.
type
]
||
b
(
this
.
type
)}
return
c
.
prototype
.
formattedValue
=
function
(
b
){
var
c
,
d
,
e
,
f
,
g
,
h
,
i
;
h
=
this
.
formatters
;
for
(
f
=
0
,
g
=
h
.
length
;
f
<
g
;
f
++
)
d
=
h
[
f
],
c
=
d
.
split
(
/
\s
+/
),
e
=
c
.
shift
(),
b
=
(
i
=
a
.
config
.
formatters
)[
e
].
apply
(
i
,[
b
].
concat
(
j
.
call
(
c
)));
return
b
},
c
.
prototype
.
set
=
function
(
a
){
return
a
=
this
.
formattedValue
(
a
),
this
.
bindType
===
"event"
?(
this
.
routine
(
this
.
el
,
a
,
this
.
currentListener
),
this
.
currentListener
=
a
):
this
.
routine
(
this
.
el
,
a
)},
c
.
prototype
.
bind
=
function
(){
a
.
config
.
adapter
.
subscribe
(
this
.
model
,
this
.
keypath
,
this
.
set
),
a
.
config
.
preloadData
&&
this
.
set
(
a
.
config
.
adapter
.
read
(
this
.
model
,
this
.
keypath
));
if
(
this
.
bindType
===
"bidirectional"
)
return
d
(
this
.
el
,
"change"
,
this
.
publish
)},
c
.
prototype
.
publish
=
function
(
b
){
var
c
;
return
c
=
b
.
target
||
b
.
srcElement
,
a
.
config
.
adapter
.
publish
(
this
.
model
,
this
.
keypath
,
f
(
c
))},
c
.
prototype
.
unbind
=
function
(){
a
.
config
.
adapter
.
unsubscribe
(
this
.
model
,
this
.
keypath
,
this
.
set
);
if
(
this
.
bindType
===
"bidirectional"
)
return
this
.
el
.
removeEventListener
(
"change"
,
this
.
publish
)},
c
}(),
a
.
View
=
function
(){
function
b
(
a
,
b
){
this
.
els
=
a
,
this
.
models
=
b
,
this
.
unbind
=
i
(
this
.
unbind
,
this
),
this
.
bind
=
i
(
this
.
bind
,
this
),
this
.
build
=
i
(
this
.
build
,
this
),
this
.
bindingRegExp
=
i
(
this
.
bindingRegExp
,
this
),
this
.
els
.
jquery
||
this
.
els
instanceof
Array
||
(
this
.
els
=
[
this
.
els
]),
this
.
build
()}
return
b
.
prototype
.
bindingRegExp
=
function
(){
var
b
;
return
b
=
a
.
config
.
prefix
,
b
?
new
RegExp
(
"^data-"
+
b
+
"-"
):
/^data-/
},
b
.
prototype
.
build
=
function
(){
var
b
,
d
,
e
,
f
,
g
,
h
,
i
,
j
,
l
,
m
=
this
;
this
.
bindings
=
[],
b
=
this
.
bindingRegExp
(),
e
=
/^on-/
,
g
=
function
(
d
){
var
f
,
g
,
h
,
i
,
j
,
l
,
n
,
o
,
p
,
q
,
r
,
s
;
r
=
d
.
attributes
,
s
=
[];
for
(
p
=
0
,
q
=
r
.
length
;
p
<
q
;
p
++
)
f
=
r
[
p
],
b
.
test
(
f
.
name
)?(
g
=
"attribute"
,
o
=
f
.
name
.
replace
(
b
,
""
),
n
=
function
(){
var
a
,
b
,
c
,
d
;
c
=
f
.
value
.
split
(
"|"
),
d
=
[];
for
(
a
=
0
,
b
=
c
.
length
;
a
<
b
;
a
++
)
l
=
c
[
a
],
d
.
push
(
l
.
trim
());
return
d
}(),
j
=
n
.
shift
().
split
(
"."
),
i
=
m
.
models
[
j
.
shift
()],
h
=
j
.
join
(
"."
),
e
.
test
(
o
)?(
o
=
o
.
replace
(
e
,
""
),
g
=
"event"
):
k
.
call
(
c
,
o
)
>=
0
&&
(
g
=
"bidirectional"
),
s
.
push
(
m
.
bindings
.
push
(
new
a
.
Binding
(
d
,
o
,
g
,
i
,
h
,
n
)))):
s
.
push
(
void
0
);
return
s
},
j
=
this
.
els
,
l
=
[];
for
(
h
=
0
,
i
=
j
.
length
;
h
<
i
;
h
++
)
d
=
j
[
h
],
g
(
d
),
l
.
push
(
function
(){
var
a
,
b
,
c
,
e
;
c
=
d
.
getElementsByTagName
(
"*"
),
e
=
[];
for
(
a
=
0
,
b
=
c
.
length
;
a
<
b
;
a
++
)
f
=
c
[
a
],
e
.
push
(
g
(
f
));
return
e
}());
return
l
},
b
.
prototype
.
bind
=
function
(){
var
a
,
b
,
c
,
d
,
e
;
d
=
this
.
bindings
,
e
=
[];
for
(
b
=
0
,
c
=
d
.
length
;
b
<
c
;
b
++
)
a
=
d
[
b
],
e
.
push
(
a
.
bind
());
return
e
},
b
.
prototype
.
unbind
=
function
(){
var
a
,
b
,
c
,
d
,
e
;
d
=
this
.
bindings
,
e
=
[];
for
(
b
=
0
,
c
=
d
.
length
;
b
<
c
;
b
++
)
a
=
d
[
b
],
e
.
push
(
a
.
unbind
());
return
e
},
b
}(),
d
=
function
(
a
,
b
,
c
){
return
window
.
addEventListener
?
a
.
addEventListener
(
b
,
c
):
a
.
attachEvent
(
b
,
c
)},
h
=
function
(
a
,
b
,
c
){
return
window
.
removeEventListener
?
a
.
removeEventListener
(
b
,
c
):
a
.
detachEvent
(
b
,
c
)},
f
=
function
(
a
){
switch
(
a
.
type
){
case
"text"
:
case
"textarea"
:
case
"password"
:
case
"select-one"
:
case
"radio"
:
return
a
.
value
;
case
"checkbox"
:
return
a
.
checked
}},
e
=
function
(
a
){
return
function
(
b
,
c
,
e
){
c
&&
d
(
b
,
a
,
c
);
if
(
e
)
return
h
(
b
,
a
,
e
)}},
b
=
function
(
a
){
return
function
(
b
,
c
){
return
c
?
b
.
setAttribute
(
a
,
c
):
b
.
removeAttribute
(
a
)}},
c
=
[
"value"
,
"checked"
,
"unchecked"
],
a
.
routines
=
{
enabled
:
function
(
a
,
b
){
return
a
.
disabled
=!
b
},
disabled
:
function
(
a
,
b
){
return
a
.
disabled
=!!
b
},
checked
:
function
(
a
,
b
){
return
a
.
type
===
"radio"
?
a
.
checked
=
a
.
value
===
b
:
a
.
checked
=!!
b
},
unchecked
:
function
(
a
,
b
){
return
a
.
type
===
"radio"
?
a
.
checked
=
a
.
value
!==
b
:
a
.
checked
=!
b
},
show
:
function
(
a
,
b
){
return
a
.
style
.
display
=
b
?
""
:
"none"
},
hide
:
function
(
a
,
b
){
return
a
.
style
.
display
=
b
?
"none"
:
""
},
html
:
function
(
a
,
b
){
return
a
.
innerHTML
=
b
||
""
},
value
:
function
(
a
,
b
){
return
a
.
value
=
b
||
""
},
text
:
function
(
a
,
b
){
return
a
.
innerText
!=
null
?
a
.
innerText
=
b
||
""
:
a
.
textContent
=
b
||
""
}},
a
.
config
=
{
preloadData
:
!
0
},
g
=
{
routines
:
a
.
routines
,
config
:
a
.
config
,
configure
:
function
(
b
){
var
c
,
d
,
e
;
b
==
null
&&
(
b
=
{}),
e
=
[];
for
(
c
in
b
)
d
=
b
[
c
],
e
.
push
(
a
.
config
[
c
]
=
d
);
return
e
},
bind
:
function
(
b
,
c
){
var
d
;
return
c
==
null
&&
(
c
=
{}),
d
=
new
a
.
View
(
b
,
c
),
d
.
bind
(),
d
}},
typeof
module
!=
"undefined"
&&
module
!==
null
?
module
.
exports
=
g
:
this
.
rivets
=
g
}).
call
(
this
);
\ No newline at end of file
(
function
(){
var
a
,
b
,
c
,
d
,
e
,
f
,
g
,
h
=
function
(
a
,
b
){
return
function
(){
return
a
.
apply
(
b
,
arguments
)}},
i
=
[].
slice
,
j
=
[].
indexOf
||
function
(
a
){
for
(
var
b
=
0
,
c
=
this
.
length
;
b
<
c
;
b
++
)
if
(
b
in
this
&&
this
[
b
]
===
a
)
return
b
;
return
-
1
};
a
=
{},
String
.
prototype
.
trim
||
(
String
.
prototype
.
trim
=
function
(){
return
this
.
replace
(
/^
\s
+|
\s
+$/g
,
""
)}),
a
.
Binding
=
function
(){
function
f
(
c
,
e
,
f
,
g
,
i
){
this
.
el
=
c
,
this
.
type
=
e
,
this
.
model
=
f
,
this
.
keypath
=
g
,
this
.
options
=
i
!=
null
?
i
:{},
this
.
unbind
=
h
(
this
.
unbind
,
this
),
this
.
publish
=
h
(
this
.
publish
,
this
),
this
.
bind
=
h
(
this
.
bind
,
this
),
this
.
set
=
h
(
this
.
set
,
this
),
this
.
formattedValue
=
h
(
this
.
formattedValue
,
this
),
this
.
options
.
special
===
"event"
?
this
.
routine
=
d
(
this
.
type
):
this
.
routine
=
a
.
routines
[
this
.
type
]
||
b
(
this
.
type
),
this
.
formatters
=
this
.
options
.
formatters
||
[]}
return
f
.
prototype
.
bidirectionals
=
[
"value"
,
"checked"
,
"unchecked"
],
f
.
prototype
.
formattedValue
=
function
(
b
){
var
c
,
d
,
e
,
f
,
g
,
h
,
j
,
k
;
h
=
this
.
formatters
;
for
(
f
=
0
,
g
=
h
.
length
;
f
<
g
;
f
++
)
d
=
h
[
f
],
c
=
d
.
split
(
/
\s
+/
),
e
=
c
.
shift
(),
b
=
a
.
config
.
formatters
&&
a
.
config
.
formatters
[
e
]?(
j
=
a
.
config
.
formatters
)[
e
].
apply
(
j
,[
b
].
concat
(
i
.
call
(
c
))):(
k
=
this
.
model
)[
e
].
apply
(
k
,[
b
].
concat
(
i
.
call
(
c
)));
return
b
},
f
.
prototype
.
set
=
function
(
a
){
return
a
=
this
.
formattedValue
(
a
),
this
.
options
.
special
===
"event"
?(
this
.
routine
(
this
.
el
,
a
,
this
.
currentListener
),
this
.
currentListener
=
a
):(
a
instanceof
Function
&&
(
a
=
a
()),
this
.
routine
(
this
.
el
,
a
))},
f
.
prototype
.
bind
=
function
(){
var
b
;
this
.
options
.
bypass
?
this
.
set
(
this
.
model
[
this
.
keypath
]):(
a
.
config
.
adapter
.
subscribe
(
this
.
model
,
this
.
keypath
,
this
.
set
),
a
.
config
.
preloadData
&&
this
.
set
(
a
.
config
.
adapter
.
read
(
this
.
model
,
this
.
keypath
)));
if
(
b
=
this
.
type
,
j
.
call
(
this
.
bidirectionals
,
b
)
>=
0
)
return
c
(
this
.
el
,
"change"
,
this
.
publish
)},
f
.
prototype
.
publish
=
function
(
b
){
var
c
;
return
c
=
b
.
target
||
b
.
srcElement
,
a
.
config
.
adapter
.
publish
(
this
.
model
,
this
.
keypath
,
e
(
c
))},
f
.
prototype
.
unbind
=
function
(){
var
b
;
a
.
config
.
adapter
.
unsubscribe
(
this
.
model
,
this
.
keypath
,
this
.
set
);
if
(
b
=
this
.
type
,
j
.
call
(
this
.
bidirectionals
,
b
)
>=
0
)
return
this
.
el
.
removeEventListener
(
"change"
,
this
.
publish
)},
f
}(),
a
.
View
=
function
(){
function
b
(
a
,
b
){
this
.
els
=
a
,
this
.
models
=
b
,
this
.
unbind
=
h
(
this
.
unbind
,
this
),
this
.
bind
=
h
(
this
.
bind
,
this
),
this
.
build
=
h
(
this
.
build
,
this
),
this
.
bindingRegExp
=
h
(
this
.
bindingRegExp
,
this
),
this
.
els
.
jquery
||
this
.
els
instanceof
Array
||
(
this
.
els
=
[
this
.
els
]),
this
.
build
()}
return
b
.
prototype
.
bindingRegExp
=
function
(){
var
b
;
return
b
=
a
.
config
.
prefix
,
b
?
new
RegExp
(
"^data-"
+
b
+
"-"
):
/^data-/
},
b
.
prototype
.
build
=
function
(){
var
b
,
c
,
d
,
e
,
f
,
g
,
h
,
i
,
j
,
k
=
this
;
this
.
bindings
=
[],
b
=
this
.
bindingRegExp
(),
d
=
/^on-/
,
f
=
function
(
c
){
var
e
,
f
,
g
,
h
,
i
,
j
,
l
,
m
,
n
,
o
,
p
,
q
;
p
=
c
.
attributes
,
q
=
[];
for
(
n
=
0
,
o
=
p
.
length
;
n
<
o
;
n
++
)
e
=
p
[
n
],
b
.
test
(
e
.
name
)?(
h
=
{},
m
=
e
.
name
.
replace
(
b
,
""
),
l
=
function
(){
var
a
,
b
,
c
,
d
;
c
=
e
.
value
.
split
(
"|"
),
d
=
[];
for
(
a
=
0
,
b
=
c
.
length
;
a
<
b
;
a
++
)
j
=
c
[
a
],
d
.
push
(
j
.
trim
());
return
d
}(),
i
=
l
.
shift
().
split
(
/
(\.
|:
)
/
),
h
.
formatters
=
l
,
g
=
k
.
models
[
i
.
shift
()],
h
.
bypass
=
i
.
shift
()
===
":"
,
f
=
i
.
join
(),
d
.
test
(
m
)
&&
(
m
=
m
.
replace
(
d
,
""
),
h
.
special
=
"event"
),
q
.
push
(
k
.
bindings
.
push
(
new
a
.
Binding
(
c
,
m
,
g
,
f
,
h
)))):
q
.
push
(
void
0
);
return
q
},
i
=
this
.
els
,
j
=
[];
for
(
g
=
0
,
h
=
i
.
length
;
g
<
h
;
g
++
)
c
=
i
[
g
],
f
(
c
),
j
.
push
(
function
(){
var
a
,
b
,
d
,
g
;
d
=
c
.
getElementsByTagName
(
"*"
),
g
=
[];
for
(
a
=
0
,
b
=
d
.
length
;
a
<
b
;
a
++
)
e
=
d
[
a
],
g
.
push
(
f
(
e
));
return
g
}());
return
j
},
b
.
prototype
.
bind
=
function
(){
var
a
,
b
,
c
,
d
,
e
;
d
=
this
.
bindings
,
e
=
[];
for
(
b
=
0
,
c
=
d
.
length
;
b
<
c
;
b
++
)
a
=
d
[
b
],
e
.
push
(
a
.
bind
());
return
e
},
b
.
prototype
.
unbind
=
function
(){
var
a
,
b
,
c
,
d
,
e
;
d
=
this
.
bindings
,
e
=
[];
for
(
b
=
0
,
c
=
d
.
length
;
b
<
c
;
b
++
)
a
=
d
[
b
],
e
.
push
(
a
.
unbind
());
return
e
},
b
}(),
c
=
function
(
a
,
b
,
c
){
return
window
.
addEventListener
?
a
.
addEventListener
(
b
,
c
):
a
.
attachEvent
(
b
,
c
)},
g
=
function
(
a
,
b
,
c
){
return
window
.
removeEventListener
?
a
.
removeEventListener
(
b
,
c
):
a
.
detachEvent
(
b
,
c
)},
e
=
function
(
a
){
switch
(
a
.
type
){
case
"text"
:
case
"textarea"
:
case
"password"
:
case
"select-one"
:
case
"radio"
:
return
a
.
value
;
case
"checkbox"
:
return
a
.
checked
}},
d
=
function
(
a
){
return
function
(
b
,
d
,
e
){
d
&&
c
(
b
,
a
,
d
);
if
(
e
)
return
g
(
b
,
a
,
e
)}},
b
=
function
(
a
){
return
function
(
b
,
c
){
return
c
?
b
.
setAttribute
(
a
,
c
):
b
.
removeAttribute
(
a
)}},
a
.
routines
=
{
enabled
:
function
(
a
,
b
){
return
a
.
disabled
=!
b
},
disabled
:
function
(
a
,
b
){
return
a
.
disabled
=!!
b
},
checked
:
function
(
a
,
b
){
return
a
.
type
===
"radio"
?
a
.
checked
=
a
.
value
===
b
:
a
.
checked
=!!
b
},
unchecked
:
function
(
a
,
b
){
return
a
.
type
===
"radio"
?
a
.
checked
=
a
.
value
!==
b
:
a
.
checked
=!
b
},
show
:
function
(
a
,
b
){
return
a
.
style
.
display
=
b
?
""
:
"none"
},
hide
:
function
(
a
,
b
){
return
a
.
style
.
display
=
b
?
"none"
:
""
},
html
:
function
(
a
,
b
){
return
a
.
innerHTML
=
b
||
""
},
value
:
function
(
a
,
b
){
return
a
.
value
=
b
||
""
},
text
:
function
(
a
,
b
){
return
a
.
innerText
!=
null
?
a
.
innerText
=
b
||
""
:
a
.
textContent
=
b
||
""
}},
a
.
config
=
{
preloadData
:
!
0
},
f
=
{
routines
:
a
.
routines
,
config
:
a
.
config
,
configure
:
function
(
b
){
var
c
,
d
,
e
;
b
==
null
&&
(
b
=
{}),
e
=
[];
for
(
c
in
b
)
d
=
b
[
c
],
e
.
push
(
a
.
config
[
c
]
=
d
);
return
e
},
bind
:
function
(
b
,
c
){
var
d
;
return
c
==
null
&&
(
c
=
{}),
d
=
new
a
.
View
(
b
,
c
),
d
.
bind
(),
d
}},
typeof
module
!=
"undefined"
&&
module
!==
null
?
module
.
exports
=
f
:
this
.
rivets
=
f
}).
call
(
this
);
\ No newline at end of file
...
...
spec/rivets/binding.js
View file @
962107e
...
...
@@ -22,6 +22,41 @@ describe('Rivets.Binding', function() {
expect
(
binding
.
routine
).
toBe
(
rivets
.
routines
.
text
);
});
describe
(
'bind()'
,
function
()
{
it
(
'subscribes to the model for changes via the adapter'
,
function
()
{
spyOn
(
rivets
.
config
.
adapter
,
'subscribe'
);
binding
.
bind
();
expect
(
rivets
.
config
.
adapter
.
subscribe
).
toHaveBeenCalled
();
});
describe
(
'with preloadData set to true'
,
function
()
{
beforeEach
(
function
()
{
rivets
.
config
.
preloadData
=
true
;
});
it
(
'sets the initial value via the adapter'
,
function
()
{
spyOn
(
binding
,
'set'
);
spyOn
(
rivets
.
config
.
adapter
,
'read'
);
binding
.
bind
();
expect
(
binding
.
set
).
toHaveBeenCalled
();
expect
(
rivets
.
config
.
adapter
.
read
).
toHaveBeenCalled
();
});
});
describe
(
'with the bypass option set to true'
,
function
()
{
beforeEach
(
function
()
{
binding
.
options
.
bypass
=
true
;
});
it
(
'sets the initial value from the model directly'
,
function
()
{
spyOn
(
binding
,
'set'
);
binding
.
model
.
name
=
'espresso'
;
binding
.
bind
();
expect
(
binding
.
set
).
toHaveBeenCalledWith
(
'espresso'
);
});
});
});
describe
(
'set()'
,
function
()
{
it
(
'performs the binding routine with the supplied value'
,
function
()
{
spyOn
(
binding
,
'routine'
);
...
...
@@ -41,7 +76,7 @@ describe('Rivets.Binding', function() {
describe
(
'on an event binding'
,
function
()
{
beforeEach
(
function
()
{
binding
.
bindType
=
'event'
;
binding
.
options
.
special
=
'event'
;
});
it
(
'performs the binding routine with the supplied function and current listener'
,
function
()
{
...
...
src/rivets.coffee
View file @
962107e
...
...
@@ -12,14 +12,20 @@ unless String::trim then String::trim = -> @replace /^\s+|\s+$/g, ""
# A single binding between a model attribute and a DOM element.
class
Rivets
.
Binding
# All information about the binding is passed into the constructor; the DOM
# element, the
routine identifier
, the model object and the keypath at which
# element, the
type of binding
, the model object and the keypath at which
# to listen for changes.
constructor
:
(
@
el
,
@
type
,
@
bindType
,
@
model
,
@
keypath
,
@
formatters
=
[]
)
->
if
@
bindType
is
"event"
constructor
:
(
@
el
,
@
type
,
@
model
,
@
keypath
,
@
options
=
{}
)
->
if
@
options
.
special
is
"event"
@
routine
=
eventBinding
@
type
else
@
routine
=
Rivets
.
routines
[
@
type
]
||
attributeBinding
@
type
@
formatters
=
@
options
.
formatters
||
[]
# Bindings that should also observe the DOM element for changes in order to
# propagate those changes back to the model object.
bidirectionals
:
[
'value'
,
'checked'
,
'unchecked'
]
# Applies all the current formatters to the supplied value and returns the
# formatted value.
formattedValue
:
(
value
)
=>
...
...
@@ -38,22 +44,26 @@ class Rivets.Binding
set
:
(
value
)
=>
value
=
@
formattedValue
value
if
@
bindType
is
"event"
if
@
options
.
special
is
"event"
@
routine
@
el
,
value
,
@
currentListener
@
currentListener
=
value
else
value
=
value
()
if
value
instanceof
Function
@
routine
@
el
,
value
# Subscribes to the model for changes at the specified keypath. Bi-directional
# routines will also listen for changes on the element to propagate them back
# to the model.
bind
:
=>
Rivets
.
config
.
adapter
.
subscribe
@
model
,
@
keypath
,
@
set
if
@
options
.
bypass
@
set
@
model
[
@
keypath
]
else
Rivets
.
config
.
adapter
.
subscribe
@
model
,
@
keypath
,
@
set
if
Rivets
.
config
.
preloadData
@
set
Rivets
.
config
.
adapter
.
read
@
model
,
@
keypath
if
Rivets
.
config
.
preloadData
@
set
Rivets
.
config
.
adapter
.
read
@
model
,
@
keypath
if
@
bindType
is
"bidirectional"
if
@
type
in
@
bidirectionals
bindEvent
@
el
,
'change'
,
@
publish
# Publishes the value currently set on the input element back to the model.
...
...
@@ -65,7 +75,7 @@ class Rivets.Binding
unbind
:
=>
Rivets
.
config
.
adapter
.
unsubscribe
@
model
,
@
keypath
,
@
set
if
@
bindType
is
"bidirectional"
if
@
type
in
@
bidirectionals
@
el
.
removeEventListener
'change'
,
@
publish
# A collection of bindings built from a set of parent elements.
...
...
@@ -90,20 +100,21 @@ class Rivets.View
parseNode
=
(
node
)
=>
for
attribute
in
node
.
attributes
if
bindingRegExp
.
test
attribute
.
name
bindType
=
"attribute"
options
=
{}
type
=
attribute
.
name
.
replace
bindingRegExp
,
''
pipes
=
(
pipe
.
trim
()
for
pipe
in
attribute
.
value
.
split
'|'
)
path
=
pipes
.
shift
().
split
'.'
path
=
pipes
.
shift
().
split
(
/(\.|:)/
)
options
.
formatters
=
pipes
model
=
@
models
[
path
.
shift
()]
keypath
=
path
.
join
'.'
options
.
bypass
=
path
.
shift
()
is
':'
keypath
=
path
.
join
()
if
eventRegExp
.
test
type
type
=
type
.
replace
eventRegExp
,
''
bindType
=
"event"
else
if
type
in
bidirectionals
bindType
=
"bidirectional"
options
.
special
=
"event"
@
bindings
.
push
new
Rivets
.
Binding
node
,
type
,
bindType
,
model
,
keypath
,
pipe
s
@
bindings
.
push
new
Rivets
.
Binding
node
,
type
,
model
,
keypath
,
option
s
for
el
in
@
els
parseNode
el
...
...
@@ -140,7 +151,7 @@ getInputValue = (el) ->
when
'text'
,
'textarea'
,
'password'
,
'select-one'
,
'radio'
then
el
.
value
when
'checkbox'
then
el
.
checked
# Returns an e
lement binding routine for the specified attribute
.
# Returns an e
vent binding routine for the specified event
.
eventBinding
=
(
event
)
->
(
el
,
bind
,
unbind
)
->
bindEvent
el
,
event
,
bind
if
bind
unbindEvent
el
,
event
,
unbind
if
unbind
...
...
@@ -150,10 +161,6 @@ eventBinding = (event) -> (el, bind, unbind) ->
attributeBinding
=
(
attr
)
->
(
el
,
value
)
->
if
value
then
el
.
setAttribute
attr
,
value
else
el
.
removeAttribute
attr
# Bindings that should also be observed for changes on the DOM element in order
# to propagate those changes back to the model object.
bidirectionals
=
[
'value'
,
'checked'
,
'unchecked'
]
# Core binding routines.
Rivets
.
routines
=
enabled
:
(
el
,
value
)
->
...
...
Please
register
or
sign in
to post a comment