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
e0ecf8db
authored
2012-11-14 17:44:35 -0800
by
Michael Richards
Browse Files
Options
Browse Files
Tag
Download
Plain Diff
Merge pull request #90 from mdekmetzian/master
Support for two-way formatters [#74]
2 parents
11c6d643
24689897
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
159 additions
and
7 deletions
spec/rivets/binding.js
src/rivets.coffee
spec/rivets/binding.js
View file @
e0ecf8d
...
...
@@ -130,7 +130,7 @@ describe('Rivets.Binding', function() {
});
it
(
'applies any formatters to the value before performing the routine'
,
function
()
{
rivets
.
formatters
.
awesome
=
function
(
value
)
{
return
'awesome '
+
value
};
rivets
.
formatters
.
awesome
=
function
(
value
)
{
return
'awesome '
+
value
;
};
binding
.
formatters
.
push
(
'awesome'
);
spyOn
(
binding
.
binder
,
'routine'
);
binding
.
set
(
'sweater'
);
...
...
@@ -163,15 +163,149 @@ describe('Rivets.Binding', function() {
});
});
describe
(
'publishTwoWay()'
,
function
()
{
it
(
'applies a two-way read formatter to function same as a single-way'
,
function
()
{
rivets
.
formatters
.
awesome
=
{
read
:
function
(
value
)
{
return
'awesome '
+
value
;
},
};
binding
.
formatters
.
push
(
'awesome'
);
spyOn
(
binding
.
binder
,
'routine'
);
binding
.
set
(
'sweater'
);
expect
(
binding
.
binder
.
routine
).
toHaveBeenCalledWith
(
el
,
'awesome sweater'
);
});
it
(
"should publish the value of a number input"
,
function
()
{
rivets
.
formatters
.
awesome
=
{
publish
:
function
(
value
)
{
return
'awesome '
+
value
;
},
};
numberInput
=
document
.
createElement
(
'input'
);
numberInput
.
setAttribute
(
'type'
,
'number'
);
numberInput
.
setAttribute
(
'data-value'
,
'obj.num | awesome'
);
view
=
rivets
.
bind
(
numberInput
,
{
obj
:
{
num
:
42
}});
binding
=
view
.
bindings
[
0
];
model
=
binding
.
model
;
numberInput
.
value
=
42
;
spyOn
(
rivets
.
config
.
adapter
,
'publish'
);
binding
.
publish
({
target
:
numberInput
});
expect
(
rivets
.
config
.
adapter
.
publish
).
toHaveBeenCalledWith
(
model
,
'num'
,
'awesome 42'
);
});
it
(
"should format a value in both directions"
,
function
()
{
rivets
.
formatters
.
awesome
=
{
publish
:
function
(
value
)
{
return
'awesome '
+
value
;
},
read
:
function
(
value
)
{
return
value
+
' is awesome'
;
}
};
valueInput
=
document
.
createElement
(
'input'
);
valueInput
.
setAttribute
(
'type'
,
'text'
);
valueInput
.
setAttribute
(
'data-value'
,
'obj.name | awesome'
);
view
=
rivets
.
bind
(
valueInput
,
{
obj
:
{
name
:
'nothing'
}});
binding
=
view
.
bindings
[
0
];
model
=
binding
.
model
;
spyOn
(
rivets
.
config
.
adapter
,
'publish'
);
valueInput
.
value
=
'charles'
;
binding
.
publish
({
target
:
valueInput
});
expect
(
rivets
.
config
.
adapter
.
publish
).
toHaveBeenCalledWith
(
model
,
'name'
,
'awesome charles'
);
spyOn
(
binding
.
binder
,
'routine'
);
binding
.
set
(
'fred'
);
expect
(
binding
.
binder
.
routine
).
toHaveBeenCalledWith
(
valueInput
,
'fred is awesome'
);
});
it
(
"should not fail or format if the specified binding function doesn't exist"
,
function
()
{
rivets
.
formatters
.
awesome
=
{
};
valueInput
=
document
.
createElement
(
'input'
);
valueInput
.
setAttribute
(
'type'
,
'text'
);
valueInput
.
setAttribute
(
'data-value'
,
'obj.name | awesome'
);
view
=
rivets
.
bind
(
valueInput
,
{
obj
:
{
name
:
'nothing'
}});
binding
=
view
.
bindings
[
0
];
model
=
binding
.
model
;
spyOn
(
rivets
.
config
.
adapter
,
'publish'
);
valueInput
.
value
=
'charles'
;
binding
.
publish
({
target
:
valueInput
});
expect
(
rivets
.
config
.
adapter
.
publish
).
toHaveBeenCalledWith
(
model
,
'name'
,
'charles'
);
spyOn
(
binding
.
binder
,
'routine'
);
binding
.
set
(
'fred'
);
expect
(
binding
.
binder
.
routine
).
toHaveBeenCalledWith
(
valueInput
,
'fred'
);
});
it
(
"should apply read binders left to right, and write binders right to left"
,
function
()
{
rivets
.
formatters
.
totally
=
{
publish
:
function
(
value
)
{
return
value
+
' totally'
;
},
read
:
function
(
value
)
{
return
value
+
' totally'
;
}
};
rivets
.
formatters
.
awesome
=
{
publish
:
function
(
value
)
{
return
value
+
' is awesome'
;
},
read
:
function
(
value
)
{
return
value
+
' is awesome'
;
}
};
valueInput
=
document
.
createElement
(
'input'
);
valueInput
.
setAttribute
(
'type'
,
'text'
);
valueInput
.
setAttribute
(
'data-value'
,
'obj.name | awesome | totally'
);
view
=
rivets
.
bind
(
valueInput
,
{
obj
:
{
name
:
'nothing'
}});
binding
=
view
.
bindings
[
0
];
model
=
binding
.
model
;
spyOn
(
binding
.
binder
,
'routine'
);
binding
.
set
(
'fred'
);
expect
(
binding
.
binder
.
routine
).
toHaveBeenCalledWith
(
valueInput
,
'fred is awesome totally'
);
spyOn
(
rivets
.
config
.
adapter
,
'publish'
);
valueInput
.
value
=
'fred'
;
binding
.
publish
({
target
:
valueInput
});
expect
(
rivets
.
config
.
adapter
.
publish
).
toHaveBeenCalledWith
(
model
,
'name'
,
'fred totally is awesome'
);
});
it
(
"binders in a chain should be skipped if they're not there"
,
function
()
{
rivets
.
formatters
.
totally
=
{
publish
:
function
(
value
)
{
return
value
+
' totally'
;
},
read
:
function
(
value
)
{
return
value
+
' totally'
;
}
};
rivets
.
formatters
.
radical
=
{
publish
:
function
(
value
)
{
return
value
+
' is radical'
;
},
};
rivets
.
formatters
.
awesome
=
function
(
value
)
{
return
value
+
' is awesome'
;
};
valueInput
=
document
.
createElement
(
'input'
);
valueInput
.
setAttribute
(
'type'
,
'text'
);
valueInput
.
setAttribute
(
'data-value'
,
'obj.name | awesome | radical | totally'
);
view
=
rivets
.
bind
(
valueInput
,
{
obj
:
{
name
:
'nothing'
}});
binding
=
view
.
bindings
[
0
];
model
=
binding
.
model
;
spyOn
(
binding
.
binder
,
'routine'
);
binding
.
set
(
'fred'
);
expect
(
binding
.
binder
.
routine
).
toHaveBeenCalledWith
(
valueInput
,
'fred is awesome totally'
);
spyOn
(
rivets
.
config
.
adapter
,
'publish'
);
valueInput
.
value
=
'fred'
;
binding
.
publish
({
target
:
valueInput
});
expect
(
rivets
.
config
.
adapter
.
publish
).
toHaveBeenCalledWith
(
model
,
'name'
,
'fred totally is radical'
);
});
});
describe
(
'formattedValue()'
,
function
()
{
it
(
'applies the current formatters on the supplied value'
,
function
()
{
rivets
.
formatters
.
awesome
=
function
(
value
)
{
return
'awesome '
+
value
};
rivets
.
formatters
.
awesome
=
function
(
value
)
{
return
'awesome '
+
value
;
};
binding
.
formatters
.
push
(
'awesome'
);
expect
(
binding
.
formattedValue
(
'hat'
)).
toBe
(
'awesome hat'
);
});
it
(
'uses formatters on the model'
,
function
()
{
model
.
modelAwesome
=
function
(
value
)
{
return
'model awesome '
+
value
};
model
.
modelAwesome
=
function
(
value
)
{
return
'model awesome '
+
value
;
};
binding
.
formatters
.
push
(
'modelAwesome'
);
expect
(
binding
.
formattedValue
(
'hat'
)).
toBe
(
'model awesome hat'
);
});
...
...
src/rivets.coffee
View file @
e0ecf8d
...
...
@@ -40,8 +40,14 @@ class Rivets.Binding
value
=
if
@
model
[
id
]
instanceof
Function
@
model
[
id
]
value
,
args
...
else
if
Rivets
.
formatters
[
id
]
Rivets
.
formatters
[
id
]
value
,
args
...
if
Rivets
.
formatters
[
id
].
read
instanceof
Function
Rivets
.
formatters
[
id
].
read
value
,
args
...
else
if
Rivets
.
formatters
[
id
]
instanceof
Function
# could occur if fmt = { publish: function() {}}
Rivets
.
formatters
[
id
]
value
,
args
...
else
# skip if no read function exists
value
else
# skip if no formatter exists
value
value
# Sets the value for the binding. This Basically just runs the binding routine
...
...
@@ -62,8 +68,20 @@ class Rivets.Binding
Rivets
.
config
.
adapter
.
read
@
model
,
@
keypath
# Publishes the value currently set on the input element back to the model.
publish
:
=>
Rivets
.
config
.
adapter
.
publish
@
model
,
@
keypath
,
getInputValue
@
el
publish
:
=>
value
=
getInputValue
@
el
if
@
formatters
i
=
@
formatters
.
length
-
1
while
(
i
>
-
1
)
formatter
=
@
formatters
[
i
]
args
=
formatter
.
split
/\s+/
id
=
args
.
shift
()
# only re-assign if there is a two-way formatter.
if
Rivets
.
formatters
[
id
]
and
Rivets
.
formatters
[
id
].
publish
value
=
Rivets
.
formatters
[
id
].
publish
value
,
args
...
i
--
if
(
value
)
Rivets
.
config
.
adapter
.
publish
@
model
,
@
keypath
,
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
...
...
Please
register
or
sign in
to post a comment