knockout-rails 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/Gemfile +4 -0
- data/HISTORY.md +7 -1
- data/README.md +18 -2
- data/{vendor → lib}/assets/javascripts/knockout.js +0 -3
- data/lib/assets/javascripts/knockout/bindings/all.js +1 -0
- data/lib/assets/javascripts/knockout/bindings/autosave.js.coffee +26 -0
- data/lib/assets/javascripts/knockout/bindings/color.js.coffee +21 -0
- data/lib/assets/javascripts/knockout/bindings/inplace.js.coffee +44 -0
- data/lib/assets/javascripts/knockout/bindings/onoff.js.coffee +20 -0
- data/lib/assets/javascripts/knockout/model.js.coffee +2 -1
- data/lib/knockout-rails/version.rb +1 -1
- data/spec/javascripts/knockout/bindings/autosave_spec.js.coffee +78 -0
- data/spec/javascripts/knockout/bindings/color_spec.js.coffee +35 -0
- data/spec/javascripts/knockout/bindings/inplace_spec.js.coffee +42 -0
- data/spec/javascripts/knockout/bindings/onoff_spec.js.coffee +11 -0
- data/spec/javascripts/spec.js.coffee +3 -0
- data/vendor/assets/javascripts/knockout/knockout.js +62 -39
- metadata +28 -22
- data/Gemfile.lock +0 -134
- data/lib/assets/javascripts/knockout/bindings.js.coffee +0 -1
- data/lib/assets/javascripts/knockout/observables.js.coffee +0 -1
- data/spec/javascripts/knockout/bindings_spec.js.coffee +0 -2
- data/spec/javascripts/knockout/observables_spec.js.coffee +0 -3
data/.gitignore
CHANGED
data/Gemfile
CHANGED
data/HISTORY.md
CHANGED
@@ -1,7 +1,13 @@
|
|
1
|
-
# 0.0.
|
1
|
+
# 0.0.3 - in progress
|
2
2
|
|
3
3
|
- Support collections (fetch multiple records)
|
4
4
|
- Client side validation
|
5
|
+
- JST templating support
|
6
|
+
|
7
|
+
# 0.0.2 - 26 November 2011
|
8
|
+
|
9
|
+
- do not require bindings automatically
|
10
|
+
- includes bindings: autosave, inplace, onoff, color
|
5
11
|
|
6
12
|
# 0.0.1 - 17 November 2011
|
7
13
|
Initial release. Bare bones moved over from other project. Includes:
|
data/README.md
CHANGED
@@ -9,12 +9,12 @@ This provides a set of conveniences for you to use more like Backbone or Spine,
|
|
9
9
|
Add it to your Rails application's `Gemfile`:
|
10
10
|
|
11
11
|
```ruby
|
12
|
-
gem 'knockout'
|
12
|
+
gem 'knockout-rails'
|
13
13
|
```
|
14
14
|
|
15
15
|
Then `bundle install`.
|
16
16
|
|
17
|
-
Reference `knockout` from your JavaScript as you normally do.
|
17
|
+
Reference `knockout` from your JavaScript as you normally do with Rails 3.1 Assets Pipeline.
|
18
18
|
|
19
19
|
|
20
20
|
# Usage
|
@@ -71,6 +71,22 @@ Now let's see how we can show the validation errors on the page and bind everyth
|
|
71
71
|
%span.inline-error{:data=>{:bind=>'visible: errors.name, text: errors.name'}}
|
72
72
|
```
|
73
73
|
|
74
|
+
## Bindings
|
75
|
+
|
76
|
+
This gem also includes useful bindings that you may find useful in your application.
|
77
|
+
For example, you can use `autosave` binding by requiring `knockout/bindings/autosave`.
|
78
|
+
|
79
|
+
Or if you want to include all of the bindings available, then require `knockout/bindings/all`.
|
80
|
+
|
81
|
+
Please see the specs for more detailed instruction on how to use specific binding.
|
82
|
+
|
83
|
+
The list of currently available bindings:
|
84
|
+
|
85
|
+
- `autosave` - automatically persists the model whenever any of its attributes change.
|
86
|
+
Apply it to a `form` element. Examples: `autosave: page`, `autosave: {model: page, when: page.isEnabled, unless: viewModel.doNotSave }`.
|
87
|
+
- `inplace` - converts the input elements into inplace editing with 'Edit'/'Done' buttons. Apply it on `input` elements similarly to the `value` binding.
|
88
|
+
- `color` - converts an element into a color picker. Apply it to a `div` element: `color: page.fontColor`. Depends on [pakunok](https://github.com/dnagir/pakunok) gem (specifically - its `colorpicker` asset).
|
89
|
+
- `onoff` - Converts checkboxes into iOS on/off buttons. Example: `onoff: page.isPublic`. It depends on [ios-chechboxes](https://github.com/dnagir/ios-checkboxes) gem.
|
74
90
|
|
75
91
|
# Development
|
76
92
|
|
@@ -0,0 +1 @@
|
|
1
|
+
//=require_tree ./
|
@@ -0,0 +1,26 @@
|
|
1
|
+
valOrDefault = (val, def) ->
|
2
|
+
if val?
|
3
|
+
ko.utils.unwrapObservable val
|
4
|
+
else
|
5
|
+
def
|
6
|
+
|
7
|
+
ko.bindingHandlers.autosave =
|
8
|
+
init: (element, valueAccessor, allBindingsAccessor, viewModel) ->
|
9
|
+
form = $(element)
|
10
|
+
form.submit (e) -> e.preventDefault()
|
11
|
+
|
12
|
+
options = valueAccessor()
|
13
|
+
[ifYes, ifNo, model] = [options.when, options.unless, options.model]
|
14
|
+
|
15
|
+
model = options unless ifYes? or ifNo?
|
16
|
+
|
17
|
+
throw "Pls provide either MODEL object or: {model: yourModel, when: optionalTrueCondition, unless: optionalFalseCondition}" unless model.save
|
18
|
+
|
19
|
+
doSave = model.save.debounce(500) # Not too fast
|
20
|
+
|
21
|
+
# subscribe to all notifications of all the observable fields of the model
|
22
|
+
observables = Object.keys(model).filter((x)->ko.isObservable model[x]).map (x)->model[x]
|
23
|
+
observables.forEach (o) -> o.subscribe ->
|
24
|
+
ye = valOrDefault ifYes, true
|
25
|
+
na = valOrDefault ifNo, false
|
26
|
+
doSave() if ye and not na
|
@@ -0,0 +1,21 @@
|
|
1
|
+
#= require pakunok/colorpicker
|
2
|
+
|
3
|
+
valOf = (va)-> ko.utils.unwrapObservable(va()) or ''
|
4
|
+
|
5
|
+
picker =
|
6
|
+
init: (element, valueAccessor) ->
|
7
|
+
val = valOf valueAccessor
|
8
|
+
el = $(element)
|
9
|
+
el.addClass('color').css('backgroundColor', val).ColorPicker
|
10
|
+
color: val
|
11
|
+
onChange: (hsb, hex, rgb) ->
|
12
|
+
newVal = "rgb(#{rgb.r}, #{rgb.g}, #{rgb.b})"
|
13
|
+
valueAccessor() newVal
|
14
|
+
|
15
|
+
update: (element, valueAccessor) ->
|
16
|
+
newValue = valOf valueAccessor
|
17
|
+
$(element).css('backgroundColor', newValue)
|
18
|
+
|
19
|
+
|
20
|
+
|
21
|
+
ko.bindingHandlers.color = picker
|
@@ -0,0 +1,44 @@
|
|
1
|
+
showInput = (element, showOrHide, valueAccessor) ->
|
2
|
+
el = $(element)
|
3
|
+
editable = el.next()
|
4
|
+
button = editable.next()
|
5
|
+
editable.toggle(!showOrHide)
|
6
|
+
el.toggle(showOrHide)
|
7
|
+
val = ko.utils.unwrapObservable valueAccessor()
|
8
|
+
if showOrHide
|
9
|
+
button.text 'Done'
|
10
|
+
el.val val
|
11
|
+
else
|
12
|
+
button.text 'Edit'
|
13
|
+
editable.text val
|
14
|
+
|
15
|
+
|
16
|
+
toggle = (element, valueAccessor) ->
|
17
|
+
showingInput = not editing(element)
|
18
|
+
showInput element, showingInput, valueAccessor
|
19
|
+
|
20
|
+
updateValue = (element, valueAccessor) ->
|
21
|
+
valueAccessor()( $(element).val() )
|
22
|
+
|
23
|
+
editing = (element) -> $(element).is(':visible')
|
24
|
+
|
25
|
+
ko.bindingHandlers.inplace =
|
26
|
+
init: (element, valueAccessor) ->
|
27
|
+
val = ko.utils.unwrapObservable valueAccessor()
|
28
|
+
editable = $("<span class='editable-content' />").insertAfter(element)
|
29
|
+
button = $("<a href='#' class='inline-button'>Edit</a>").insertAfter editable
|
30
|
+
showInput element, false, valueAccessor
|
31
|
+
|
32
|
+
button.closest('form').submit ->
|
33
|
+
updateValue element, valueAccessor if editing(element)
|
34
|
+
showInput element, false, valueAccessor
|
35
|
+
button.click (e) ->
|
36
|
+
e.preventDefault()
|
37
|
+
if editing element
|
38
|
+
updateValue element, valueAccessor
|
39
|
+
else
|
40
|
+
toggle element, valueAccessor
|
41
|
+
|
42
|
+
|
43
|
+
update: (element, valueAccessor) ->
|
44
|
+
showInput element, false, valueAccessor
|
@@ -0,0 +1,20 @@
|
|
1
|
+
#= require ios-checkboxes
|
2
|
+
|
3
|
+
ko.bindingHandlers.onoff =
|
4
|
+
init: (element, valueAccessor, allBindingsAccessor) ->
|
5
|
+
initialValue = ko.utils.unwrapObservable valueAccessor()
|
6
|
+
$(element).prop('checked', initialValue).iphoneStyle
|
7
|
+
handleMargin: 0
|
8
|
+
containerRadius: 0
|
9
|
+
resizeHandle: false
|
10
|
+
resizeContainer: false
|
11
|
+
checkedLabel: 'On'
|
12
|
+
uncheckedLabel: 'Off'
|
13
|
+
onChange: (el, checked) ->
|
14
|
+
writer = valueAccessor()
|
15
|
+
writer checked
|
16
|
+
|
17
|
+
update: (element, valueAccessor) ->
|
18
|
+
el = $(element)
|
19
|
+
val = ko.utils.unwrapObservable valueAccessor()
|
20
|
+
el.prop('checked', val)
|
@@ -1,3 +1,4 @@
|
|
1
|
+
#=require jquery
|
1
2
|
|
2
3
|
# Module is taken from Spine.js
|
3
4
|
moduleKeywords = ['included', 'extended']
|
@@ -57,7 +58,7 @@ Ajax =
|
|
57
58
|
statusCode:
|
58
59
|
422: (xhr, status, errorThrown)->
|
59
60
|
errorData = JSON.parse xhr.responseText
|
60
|
-
console
|
61
|
+
console?.debug?("Validation error: ", errorData)
|
61
62
|
@updateErrors(errorData)
|
62
63
|
|
63
64
|
$.ajax(params)
|
@@ -0,0 +1,78 @@
|
|
1
|
+
#= require knockout/bindings/autosave
|
2
|
+
|
3
|
+
class Page extends ko.Model
|
4
|
+
@configure 'page'
|
5
|
+
|
6
|
+
describe "AutoSave", ->
|
7
|
+
beforeEach ->
|
8
|
+
jasmine.Ajax.useMock()
|
9
|
+
jasmine.Clock.useMock()
|
10
|
+
|
11
|
+
prepare = (bindings, viewModel) ->
|
12
|
+
page = new Page { name: 'Home' }
|
13
|
+
setFixtures "<form id='autosave' data-bind='autosave: #{bindings}' />"
|
14
|
+
form = $("#autosave")[0]
|
15
|
+
viewModel = if viewModel
|
16
|
+
ko.utils.extend viewModel, {page: page}
|
17
|
+
else
|
18
|
+
{page: page}
|
19
|
+
ko.applyBindings viewModel, form
|
20
|
+
page
|
21
|
+
|
22
|
+
|
23
|
+
|
24
|
+
it "should call 'save' when property changes and use delay", ->
|
25
|
+
model = prepare "page"
|
26
|
+
|
27
|
+
model.name 'Index'
|
28
|
+
jasmine.Clock.tick 100
|
29
|
+
expect(mostRecentAjaxRequest()).toBeFalsy()
|
30
|
+
|
31
|
+
jasmine.Clock.tick 5000
|
32
|
+
expect(mostRecentAjaxRequest()).toBeTruthy()
|
33
|
+
|
34
|
+
|
35
|
+
it "should not save when 'when' condition is falsy", ->
|
36
|
+
model = prepare "{model: page, when: shouldSave}", {shouldSave: false}
|
37
|
+
|
38
|
+
model.name 'Index'
|
39
|
+
jasmine.Clock.tick 5000
|
40
|
+
expect(mostRecentAjaxRequest()).toBeFalsy()
|
41
|
+
|
42
|
+
it "should save when 'when' condition is truthy", ->
|
43
|
+
model = prepare "{model: page, when: shouldSave}", shouldSave: ko.observable(true)
|
44
|
+
model.name 'Index'
|
45
|
+
jasmine.Clock.tick 5000
|
46
|
+
expect(mostRecentAjaxRequest()).toBeTruthy()
|
47
|
+
|
48
|
+
it "should save when 'unless' condition is falsy", ->
|
49
|
+
model = prepare "{model: page, unless: dontSave}", dontSave: false
|
50
|
+
model.name 'Index'
|
51
|
+
jasmine.Clock.tick 5000
|
52
|
+
expect(mostRecentAjaxRequest()).toBeTruthy()
|
53
|
+
|
54
|
+
it "should not save when 'unless' condition is truthy", ->
|
55
|
+
model = prepare "{model: page, unless: dontSave}", dontSave: true
|
56
|
+
model.name 'Index'
|
57
|
+
jasmine.Clock.tick 5000
|
58
|
+
expect(mostRecentAjaxRequest()).toBeFalsy()
|
59
|
+
|
60
|
+
it "should save with when=true, unless=false", ->
|
61
|
+
model = prepare "{model: page, when: shouldSave, unless: dontSave}", shouldSave: true, dontSave: false
|
62
|
+
model.name 'Index'
|
63
|
+
jasmine.Clock.tick 5000
|
64
|
+
expect(mostRecentAjaxRequest()).toBeTruthy()
|
65
|
+
|
66
|
+
it "should not save with when=false, unless=false", ->
|
67
|
+
model = prepare "{model: page, when: shouldSave, unless: dontSave}", shouldSave: false, dontSave: false
|
68
|
+
model.name 'Index'
|
69
|
+
jasmine.Clock.tick 5000
|
70
|
+
expect(mostRecentAjaxRequest()).toBeFalsy()
|
71
|
+
|
72
|
+
|
73
|
+
it "should not save with when=true, unless=true", ->
|
74
|
+
model = prepare "{model: page, when: shouldSave, unless: dontSave}", shouldSave: true, dontSave: true
|
75
|
+
model.name 'Index'
|
76
|
+
jasmine.Clock.tick 5000
|
77
|
+
expect(mostRecentAjaxRequest()).toBeFalsy()
|
78
|
+
|
@@ -0,0 +1,35 @@
|
|
1
|
+
#= require knockout/bindings/color
|
2
|
+
|
3
|
+
describe "Color picker", ->
|
4
|
+
colorise = (color)->
|
5
|
+
setFixtures "<div id='color' data-bind='color: color' />"
|
6
|
+
el = $ '#color'
|
7
|
+
ko.applyBindings {color: color or ko.observable("rgb(1, 2, 3)")}, el[0]
|
8
|
+
el
|
9
|
+
|
10
|
+
afterEach ->
|
11
|
+
# It adds itself to the body, so is outisde of the fixure
|
12
|
+
$(".colorpicker").remove()
|
13
|
+
|
14
|
+
it "should set the initial background color", ->
|
15
|
+
el = colorise()
|
16
|
+
expect(el.css 'backgroundColor').toBe 'rgb(1, 2, 3)'
|
17
|
+
|
18
|
+
it "should add 'color' class to element", ->
|
19
|
+
el = colorise()
|
20
|
+
expect(el).toBe ".color"
|
21
|
+
|
22
|
+
|
23
|
+
it "should reflect the changed color in the UI", ->
|
24
|
+
color = ko.observable "rgb(1, 2, 3)"
|
25
|
+
el = colorise color
|
26
|
+
color "rgb(4, 5, 6)" # Modify the color here
|
27
|
+
expect(el.css 'backgroundColor').toBe 'rgb(4, 5, 6)'
|
28
|
+
|
29
|
+
|
30
|
+
it "should update the value when user changes the color", ->
|
31
|
+
color = ko.observable "rgb(1, 2, 3)"
|
32
|
+
el = colorise color
|
33
|
+
$(".colorpicker").data('colorpicker').onChange "hsb", "hex", {r: 4, g: 5, b: 6}
|
34
|
+
expect(color()).toBe 'rgb(4, 5, 6)'
|
35
|
+
|
@@ -0,0 +1,42 @@
|
|
1
|
+
#= require knockout/bindings/inplace
|
2
|
+
|
3
|
+
describe "In-Place edit", ->
|
4
|
+
|
5
|
+
inplacify = (val) ->
|
6
|
+
setFixtures "<input id='el' data-bind='inplace: val' />"
|
7
|
+
el = $('#el')
|
8
|
+
ko.applyBindings { val: val or ko.observable() }, @el[0]
|
9
|
+
el
|
10
|
+
|
11
|
+
it "should hide input initially", ->
|
12
|
+
el = inplacify()
|
13
|
+
expect(el).toBeHidden()
|
14
|
+
|
15
|
+
it "should show the current value", ->
|
16
|
+
val = ko.observable 'hi there'
|
17
|
+
el = inplacify val
|
18
|
+
expect(el.parent().find '.editable-content').toHaveText 'hi there'
|
19
|
+
|
20
|
+
it "should create an Edit link", ->
|
21
|
+
el = inplacify()
|
22
|
+
expect(el.parent()).toContain "a.inline-button"
|
23
|
+
|
24
|
+
it "should show input when clicking the Edit link", ->
|
25
|
+
el = inplacify()
|
26
|
+
el.parent().find('a.inline-button').click()
|
27
|
+
expect(el).toBeVisible()
|
28
|
+
|
29
|
+
it "should not update the value on 'change' event", ->
|
30
|
+
val = ko.observable 'Initial'
|
31
|
+
el = inplacify val
|
32
|
+
el.val 'from dom'
|
33
|
+
el.change()
|
34
|
+
expect(val()).toBe 'Initial'
|
35
|
+
|
36
|
+
it "should update the value clicking Done", ->
|
37
|
+
val = ko.observable 'initial'
|
38
|
+
el = inplacify val
|
39
|
+
el.parent().find('.inline-button').click() # Edit
|
40
|
+
el.val('updated')
|
41
|
+
el.parent().find('.inline-button').click() # Done
|
42
|
+
expect( val() ).toBe 'updated'
|
@@ -0,0 +1,11 @@
|
|
1
|
+
#= require knockout/bindings/onoff
|
2
|
+
|
3
|
+
describe "iOS Style Checkboxes", ->
|
4
|
+
iphonify = ->
|
5
|
+
setFixtures "<input id='check' type='checkbox' data-bind='onoff: isVisible' />"
|
6
|
+
el = $ '#check'
|
7
|
+
ko.applyBindings {isVisible: ko.observable(true)}, el[0]
|
8
|
+
el
|
9
|
+
|
10
|
+
it "should convert checkboxe into button", ->
|
11
|
+
expect(iphonify().parent()).toBe ".iPhoneCheckContainer"
|
@@ -1,4 +1,4 @@
|
|
1
|
-
// Knockout JavaScript library v1.3.
|
1
|
+
// Knockout JavaScript library v1.3.0rc
|
2
2
|
// (c) Steven Sanderson - http://knockoutjs.com/
|
3
3
|
// License: MIT (http://www.opensource.org/licenses/mit-license.php)
|
4
4
|
|
@@ -567,7 +567,12 @@ ko.exportSymbol('ko.utils.domNodeDisposal.removeDisposeCallback', ko.utils.domNo
|
|
567
567
|
|
568
568
|
// Go to html and back, then peel off extra wrappers
|
569
569
|
// Note that we always prefix with some dummy text, because otherwise, IE<9 will strip out leading comment nodes in descendants. Total madness.
|
570
|
-
|
570
|
+
var markup = "ignored<div>" + wrap[1] + html + wrap[2] + "</div>";
|
571
|
+
if (typeof window['innerShiv'] == "function") {
|
572
|
+
div.appendChild(window['innerShiv'](markup));
|
573
|
+
} else {
|
574
|
+
div.innerHTML = markup;
|
575
|
+
}
|
571
576
|
|
572
577
|
// Move to the right depth
|
573
578
|
while (wrap[0]--)
|
@@ -604,6 +609,7 @@ ko.exportSymbol('ko.utils.domNodeDisposal.removeDisposeCallback', ko.utils.domNo
|
|
604
609
|
})();
|
605
610
|
|
606
611
|
ko.exportSymbol('ko.utils.parseHtmlFragment', ko.utils.parseHtmlFragment);
|
612
|
+
ko.exportSymbol('ko.utils.setHtml', ko.utils.setHtml);
|
607
613
|
ko.memoization = (function () {
|
608
614
|
var memos = {};
|
609
615
|
|
@@ -712,7 +718,7 @@ function applyExtenders(requestedExtenders) {
|
|
712
718
|
ko.exportSymbol('ko.extenders', ko.extenders);
|
713
719
|
ko.subscription = function (callback, disposeCallback) {
|
714
720
|
this.callback = callback;
|
715
|
-
this.disposeCallback = disposeCallback;
|
721
|
+
this.disposeCallback = disposeCallback;
|
716
722
|
ko.exportProperty(this, 'dispose', this.dispose);
|
717
723
|
};
|
718
724
|
ko.subscription.prototype.dispose = function () {
|
@@ -721,7 +727,7 @@ ko.subscription.prototype.dispose = function () {
|
|
721
727
|
};
|
722
728
|
|
723
729
|
ko.subscribable = function () {
|
724
|
-
this._subscriptions =
|
730
|
+
this._subscriptions = {};
|
725
731
|
|
726
732
|
ko.utils.extend(this, ko.subscribable['fn']);
|
727
733
|
ko.exportProperty(this, 'subscribe', this.subscribe);
|
@@ -730,28 +736,42 @@ ko.subscribable = function () {
|
|
730
736
|
ko.exportProperty(this, 'getSubscriptionsCount', this.getSubscriptionsCount);
|
731
737
|
}
|
732
738
|
|
739
|
+
var defaultEvent = "change";
|
740
|
+
|
733
741
|
ko.subscribable['fn'] = {
|
734
|
-
subscribe: function (callback, callbackTarget) {
|
742
|
+
subscribe: function (callback, callbackTarget, event) {
|
743
|
+
event = event || defaultEvent;
|
735
744
|
var boundCallback = callbackTarget ? callback.bind(callbackTarget) : callback;
|
736
745
|
|
737
746
|
var subscription = new ko.subscription(boundCallback, function () {
|
738
|
-
ko.utils.arrayRemoveItem(this._subscriptions, subscription);
|
747
|
+
ko.utils.arrayRemoveItem(this._subscriptions[event], subscription);
|
739
748
|
}.bind(this));
|
740
|
-
|
749
|
+
|
750
|
+
if (!this._subscriptions[event])
|
751
|
+
this._subscriptions[event] = [];
|
752
|
+
this._subscriptions[event].push(subscription);
|
741
753
|
return subscription;
|
742
754
|
},
|
743
755
|
|
744
|
-
notifySubscribers: function (valueToNotify) {
|
745
|
-
|
746
|
-
|
747
|
-
|
748
|
-
|
749
|
-
subscription
|
750
|
-
|
756
|
+
notifySubscribers: function (valueToNotify, event) {
|
757
|
+
event = event || defaultEvent;
|
758
|
+
if (this._subscriptions[event]) {
|
759
|
+
ko.utils.arrayForEach(this._subscriptions[event].slice(0), function (subscription) {
|
760
|
+
// In case a subscription was disposed during the arrayForEach cycle, check
|
761
|
+
// for isDisposed on each subscription before invoking its callback
|
762
|
+
if (subscription && (subscription.isDisposed !== true))
|
763
|
+
subscription.callback(valueToNotify);
|
764
|
+
});
|
765
|
+
}
|
751
766
|
},
|
752
767
|
|
753
768
|
getSubscriptionsCount: function () {
|
754
|
-
|
769
|
+
var total = 0;
|
770
|
+
for (var eventName in this._subscriptions) {
|
771
|
+
if (this._subscriptions.hasOwnProperty(eventName))
|
772
|
+
total += this._subscriptions[eventName].length;
|
773
|
+
}
|
774
|
+
return total;
|
755
775
|
},
|
756
776
|
|
757
777
|
extend: applyExtenders
|
@@ -800,8 +820,9 @@ ko.observable = function (initialValue) {
|
|
800
820
|
|
801
821
|
// Ignore writes if the value hasn't changed
|
802
822
|
if ((!observable['equalityComparer']) || !observable['equalityComparer'](_latestValue, arguments[0])) {
|
823
|
+
observable.valueWillMutate();
|
803
824
|
_latestValue = arguments[0];
|
804
|
-
observable.
|
825
|
+
observable.valueHasMutated();
|
805
826
|
}
|
806
827
|
return this; // Permits chained assignments
|
807
828
|
}
|
@@ -813,9 +834,11 @@ ko.observable = function (initialValue) {
|
|
813
834
|
}
|
814
835
|
ko.subscribable.call(observable);
|
815
836
|
observable.valueHasMutated = function () { observable.notifySubscribers(_latestValue); }
|
816
|
-
|
817
|
-
|
837
|
+
observable.valueWillMutate = function () { observable.notifySubscribers(_latestValue, "beforeChange"); }
|
838
|
+
ko.utils.extend(observable, ko.observable['fn']);
|
839
|
+
|
818
840
|
ko.exportProperty(observable, "valueHasMutated", observable.valueHasMutated);
|
841
|
+
ko.exportProperty(observable, "valueWillMutate", observable.valueWillMutate);
|
819
842
|
|
820
843
|
return observable;
|
821
844
|
}
|
@@ -878,6 +901,9 @@ ko.observableArray['fn'] = {
|
|
878
901
|
for (var i = 0; i < underlyingArray.length; i++) {
|
879
902
|
var value = underlyingArray[i];
|
880
903
|
if (predicate(value)) {
|
904
|
+
if (removedValues.length === 0) {
|
905
|
+
this.valueWillMutate();
|
906
|
+
}
|
881
907
|
removedValues.push(value);
|
882
908
|
underlyingArray.splice(i, 1);
|
883
909
|
i--;
|
@@ -894,6 +920,7 @@ ko.observableArray['fn'] = {
|
|
894
920
|
if (arrayOfValues === undefined) {
|
895
921
|
var underlyingArray = this();
|
896
922
|
var allValues = underlyingArray.slice(0);
|
923
|
+
this.valueWillMutate();
|
897
924
|
underlyingArray.splice(0, underlyingArray.length);
|
898
925
|
this.valueHasMutated();
|
899
926
|
return allValues;
|
@@ -909,6 +936,7 @@ ko.observableArray['fn'] = {
|
|
909
936
|
destroy: function (valueOrPredicate) {
|
910
937
|
var underlyingArray = this();
|
911
938
|
var predicate = typeof valueOrPredicate == "function" ? valueOrPredicate : function (value) { return value === valueOrPredicate; };
|
939
|
+
this.valueWillMutate();
|
912
940
|
for (var i = underlyingArray.length - 1; i >= 0; i--) {
|
913
941
|
var value = underlyingArray[i];
|
914
942
|
if (predicate(value))
|
@@ -938,9 +966,10 @@ ko.observableArray['fn'] = {
|
|
938
966
|
replace: function(oldItem, newItem) {
|
939
967
|
var index = this.indexOf(oldItem);
|
940
968
|
if (index >= 0) {
|
969
|
+
this.valueWillMutate();
|
941
970
|
this()[index] = newItem;
|
942
971
|
this.valueHasMutated();
|
943
|
-
}
|
972
|
+
}
|
944
973
|
}
|
945
974
|
}
|
946
975
|
|
@@ -948,6 +977,7 @@ ko.observableArray['fn'] = {
|
|
948
977
|
ko.utils.arrayForEach(["pop", "push", "reverse", "shift", "sort", "splice", "unshift"], function (methodName) {
|
949
978
|
ko.observableArray['fn'][methodName] = function () {
|
950
979
|
var underlyingArray = this();
|
980
|
+
this.valueWillMutate();
|
951
981
|
var methodCallResult = underlyingArray[methodName].apply(underlyingArray, arguments);
|
952
982
|
this.valueHasMutated();
|
953
983
|
return methodCallResult;
|
@@ -1035,7 +1065,9 @@ ko.dependentObservable = function (evaluatorFunctionOrOptions, evaluatorFunction
|
|
1035
1065
|
_subscriptionsToDependencies.push(subscribable.subscribe(evaluatePossiblyAsync));
|
1036
1066
|
});
|
1037
1067
|
var valueForThis = options["owner"] || evaluatorFunctionTarget; // If undefined, it will default to "window" by convention. This might change in the future.
|
1038
|
-
|
1068
|
+
var newValue = options["read"].call(valueForThis);
|
1069
|
+
dependentObservable.notifySubscribers(_latestValue, "beforeChange");
|
1070
|
+
_latestValue = newValue;
|
1039
1071
|
} finally {
|
1040
1072
|
ko.dependencyDetection.end();
|
1041
1073
|
}
|
@@ -1060,7 +1092,7 @@ ko.dependentObservable = function (evaluatorFunctionOrOptions, evaluatorFunction
|
|
1060
1092
|
ko.dependencyDetection.registerDependency(dependentObservable);
|
1061
1093
|
return _latestValue;
|
1062
1094
|
}
|
1063
|
-
}
|
1095
|
+
}
|
1064
1096
|
dependentObservable.getDependenciesCount = function () { return _subscriptionsToDependencies.length; }
|
1065
1097
|
dependentObservable.hasWriteFunction = typeof options["write"] === "function";
|
1066
1098
|
dependentObservable.dispose = function () {
|
@@ -1114,7 +1146,7 @@ ko.exportSymbol('ko.computed', ko.dependentObservable); // Make "ko.computed" an
|
|
1114
1146
|
visitedObjects = visitedObjects || new objectLookup();
|
1115
1147
|
|
1116
1148
|
rootObject = mapInputCallback(rootObject);
|
1117
|
-
var canHaveProperties = (typeof rootObject == "object") && (rootObject !== null) && (rootObject !== undefined);
|
1149
|
+
var canHaveProperties = (typeof rootObject == "object") && (rootObject !== null) && (rootObject !== undefined) && (!(rootObject instanceof Date));
|
1118
1150
|
if (!canHaveProperties)
|
1119
1151
|
return rootObject;
|
1120
1152
|
|
@@ -2042,7 +2074,7 @@ ko.bindingHandlers['options'] = {
|
|
2042
2074
|
value = [value];
|
2043
2075
|
if (allBindings['optionsCaption']) {
|
2044
2076
|
var option = document.createElement("OPTION");
|
2045
|
-
option
|
2077
|
+
ko.utils.setHtml(option, allBindings['optionsCaption']);
|
2046
2078
|
ko.selectExtensions.writeValue(option, undefined);
|
2047
2079
|
element.appendChild(option);
|
2048
2080
|
}
|
@@ -2554,7 +2586,7 @@ ko.exportSymbol('ko.templateRewriting.applyMemoizedBindingsToNextSibling', ko.te
|
|
2554
2586
|
if (this.domElement.tagName.toLowerCase() == "script")
|
2555
2587
|
this.domElement.text = valueToWrite;
|
2556
2588
|
else
|
2557
|
-
this.domElement
|
2589
|
+
ko.utils.setHtml(this.domElement, valueToWrite);
|
2558
2590
|
}
|
2559
2591
|
};
|
2560
2592
|
|
@@ -3068,13 +3100,10 @@ ko.exportSymbol('ko.nativeTemplateEngine', ko.nativeTemplateEngine);(function()
|
|
3068
3100
|
// Note that as of Knockout 1.3, we only support jQuery.tmpl 1.0.0pre and later,
|
3069
3101
|
// which KO internally refers to as version "2", so older versions are no longer detected.
|
3070
3102
|
var jQueryTmplVersion = this.jQueryTmplVersion = (function() {
|
3071
|
-
if ((typeof(jQuery) == "undefined") || !(jQuery['tmpl']
|
3103
|
+
if ((typeof(jQuery) == "undefined") || !(jQuery['tmpl']))
|
3072
3104
|
return 0;
|
3073
3105
|
// Since it exposes no official version number, we use our own numbering system. To be updated as jquery-tmpl evolves.
|
3074
3106
|
try {
|
3075
|
-
if (jQuery['render'])
|
3076
|
-
return 3; // Current preview of jsRender
|
3077
|
-
|
3078
3107
|
if (jQuery['tmpl']['tag']['tmpl']['open'].toString().indexOf('__') >= 0) {
|
3079
3108
|
// Since 1.0.0pre, custom tags should append markup to an array called "__"
|
3080
3109
|
return 2; // Final version of jquery.tmpl
|
@@ -3090,11 +3119,7 @@ ko.exportSymbol('ko.nativeTemplateEngine', ko.nativeTemplateEngine);(function()
|
|
3090
3119
|
}
|
3091
3120
|
|
3092
3121
|
function executeTemplate(compiledTemplate, data, jQueryTemplateOptions) {
|
3093
|
-
|
3094
|
-
return jQuery['tmpl'](compiledTemplate, data, jQueryTemplateOptions);
|
3095
|
-
|
3096
|
-
var renderedHtml = jQuery['render'](compiledTemplate, data, jQueryTemplateOptions);
|
3097
|
-
return jQuery(ko.utils.parseHtmlFragment(renderedHtml));
|
3122
|
+
return jQuery['tmpl'](compiledTemplate, data, jQueryTemplateOptions);
|
3098
3123
|
}
|
3099
3124
|
|
3100
3125
|
this['renderTemplateSource'] = function(templateSource, bindingContext, options) {
|
@@ -3106,8 +3131,7 @@ ko.exportSymbol('ko.nativeTemplateEngine', ko.nativeTemplateEngine);(function()
|
|
3106
3131
|
if (!precompiled) {
|
3107
3132
|
var templateText = templateSource.text() || "";
|
3108
3133
|
// Wrap in "with($whatever.koBindingContext) { ... }"
|
3109
|
-
|
3110
|
-
templateText = "{{ko_with " + contextContainer + ".koBindingContext}}" + templateText + "{{/ko_with}}";
|
3134
|
+
templateText = "{{ko_with $item.koBindingContext}}" + templateText + "{{/ko_with}}";
|
3111
3135
|
|
3112
3136
|
precompiled = jQuery['template'](null, templateText);
|
3113
3137
|
templateSource['data']('precompiled', precompiled);
|
@@ -3130,12 +3154,11 @@ ko.exportSymbol('ko.nativeTemplateEngine', ko.nativeTemplateEngine);(function()
|
|
3130
3154
|
document.write("<script type='text/html' id='" + templateName + "'>" + templateMarkup + "</script>");
|
3131
3155
|
};
|
3132
3156
|
|
3133
|
-
if (jQueryTmplVersion
|
3134
|
-
|
3135
|
-
jQuery[tagContainer]['tag']['ko_code'] = {
|
3157
|
+
if (jQueryTmplVersion > 0) {
|
3158
|
+
jQuery['tmpl']['tag']['ko_code'] = {
|
3136
3159
|
open: "__.push($1 || '');"
|
3137
3160
|
};
|
3138
|
-
jQuery[
|
3161
|
+
jQuery['tmpl']['tag']['ko_with'] = {
|
3139
3162
|
open: "with($1) {",
|
3140
3163
|
close: "} "
|
3141
3164
|
};
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: knockout-rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-11-
|
12
|
+
date: 2011-11-26 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: sprockets
|
16
|
-
requirement: &
|
16
|
+
requirement: &70109798186500 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: 2.0.0
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70109798186500
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: execjs
|
27
|
-
requirement: &
|
27
|
+
requirement: &70109798186040 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70109798186040
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: jquery-rails
|
38
|
-
requirement: &
|
38
|
+
requirement: &70109798185520 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :runtime
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *70109798185520
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: rspec
|
49
|
-
requirement: &
|
49
|
+
requirement: &70109798185040 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ! '>='
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: '0'
|
55
55
|
type: :development
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *70109798185040
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: rails
|
60
|
-
requirement: &
|
60
|
+
requirement: &70109798184540 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ! '>='
|
@@ -65,7 +65,7 @@ dependencies:
|
|
65
65
|
version: 3.1.1
|
66
66
|
type: :development
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *70109798184540
|
69
69
|
description: Include the knockout.js and some of its extensions so you can pick what
|
70
70
|
you need. Adds the support for models and interation with the Rails backend.
|
71
71
|
email:
|
@@ -76,14 +76,17 @@ extra_rdoc_files: []
|
|
76
76
|
files:
|
77
77
|
- .gitignore
|
78
78
|
- Gemfile
|
79
|
-
- Gemfile.lock
|
80
79
|
- HISTORY.md
|
81
80
|
- README.md
|
82
81
|
- Rakefile
|
83
82
|
- knockout-rails.gemspec
|
84
|
-
- lib/assets/javascripts/knockout
|
83
|
+
- lib/assets/javascripts/knockout.js
|
84
|
+
- lib/assets/javascripts/knockout/bindings/all.js
|
85
|
+
- lib/assets/javascripts/knockout/bindings/autosave.js.coffee
|
86
|
+
- lib/assets/javascripts/knockout/bindings/color.js.coffee
|
87
|
+
- lib/assets/javascripts/knockout/bindings/inplace.js.coffee
|
88
|
+
- lib/assets/javascripts/knockout/bindings/onoff.js.coffee
|
85
89
|
- lib/assets/javascripts/knockout/model.js.coffee
|
86
|
-
- lib/assets/javascripts/knockout/observables.js.coffee
|
87
90
|
- lib/knockout-rails.rb
|
88
91
|
- lib/knockout-rails/engine.rb
|
89
92
|
- lib/knockout-rails/version.rb
|
@@ -118,9 +121,11 @@ files:
|
|
118
121
|
- spec/dummy/public/500.html
|
119
122
|
- spec/dummy/public/favicon.ico
|
120
123
|
- spec/dummy/script/rails
|
121
|
-
- spec/javascripts/knockout/
|
124
|
+
- spec/javascripts/knockout/bindings/autosave_spec.js.coffee
|
125
|
+
- spec/javascripts/knockout/bindings/color_spec.js.coffee
|
126
|
+
- spec/javascripts/knockout/bindings/inplace_spec.js.coffee
|
127
|
+
- spec/javascripts/knockout/bindings/onoff_spec.js.coffee
|
122
128
|
- spec/javascripts/knockout/model_spec.js.coffee
|
123
|
-
- spec/javascripts/knockout/observables_spec.js.coffee
|
124
129
|
- spec/javascripts/spec.css
|
125
130
|
- spec/javascripts/spec.js.coffee
|
126
131
|
- spec/javascripts/support/mock-ajax.js
|
@@ -128,7 +133,6 @@ files:
|
|
128
133
|
- spec/spec_helper.rb
|
129
134
|
- spec/support/global.rb
|
130
135
|
- spec/support/matchers.rb
|
131
|
-
- vendor/assets/javascripts/knockout.js
|
132
136
|
- vendor/assets/javascripts/knockout/knockout.js
|
133
137
|
- vendor/assets/javascripts/knockout/knockout.mapping.js
|
134
138
|
- vendor/assets/javascripts/knockout/sugar-1.1.1.js
|
@@ -146,7 +150,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
146
150
|
version: '0'
|
147
151
|
segments:
|
148
152
|
- 0
|
149
|
-
hash: -
|
153
|
+
hash: -2773506954842837936
|
150
154
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
151
155
|
none: false
|
152
156
|
requirements:
|
@@ -155,7 +159,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
155
159
|
version: '0'
|
156
160
|
segments:
|
157
161
|
- 0
|
158
|
-
hash: -
|
162
|
+
hash: -2773506954842837936
|
159
163
|
requirements: []
|
160
164
|
rubyforge_project: knockout-rails
|
161
165
|
rubygems_version: 1.8.10
|
@@ -194,9 +198,11 @@ test_files:
|
|
194
198
|
- spec/dummy/public/500.html
|
195
199
|
- spec/dummy/public/favicon.ico
|
196
200
|
- spec/dummy/script/rails
|
197
|
-
- spec/javascripts/knockout/
|
201
|
+
- spec/javascripts/knockout/bindings/autosave_spec.js.coffee
|
202
|
+
- spec/javascripts/knockout/bindings/color_spec.js.coffee
|
203
|
+
- spec/javascripts/knockout/bindings/inplace_spec.js.coffee
|
204
|
+
- spec/javascripts/knockout/bindings/onoff_spec.js.coffee
|
198
205
|
- spec/javascripts/knockout/model_spec.js.coffee
|
199
|
-
- spec/javascripts/knockout/observables_spec.js.coffee
|
200
206
|
- spec/javascripts/spec.css
|
201
207
|
- spec/javascripts/spec.js.coffee
|
202
208
|
- spec/javascripts/support/mock-ajax.js
|
data/Gemfile.lock
DELETED
@@ -1,134 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: .
|
3
|
-
specs:
|
4
|
-
knockout-rails (0.0.1)
|
5
|
-
execjs
|
6
|
-
jquery-rails
|
7
|
-
sprockets (>= 2.0.0)
|
8
|
-
|
9
|
-
GEM
|
10
|
-
remote: http://rubygems.org/
|
11
|
-
specs:
|
12
|
-
actionmailer (3.1.1)
|
13
|
-
actionpack (= 3.1.1)
|
14
|
-
mail (~> 2.3.0)
|
15
|
-
actionpack (3.1.1)
|
16
|
-
activemodel (= 3.1.1)
|
17
|
-
activesupport (= 3.1.1)
|
18
|
-
builder (~> 3.0.0)
|
19
|
-
erubis (~> 2.7.0)
|
20
|
-
i18n (~> 0.6)
|
21
|
-
rack (~> 1.3.2)
|
22
|
-
rack-cache (~> 1.1)
|
23
|
-
rack-mount (~> 0.8.2)
|
24
|
-
rack-test (~> 0.6.1)
|
25
|
-
sprockets (~> 2.0.2)
|
26
|
-
activemodel (3.1.1)
|
27
|
-
activesupport (= 3.1.1)
|
28
|
-
builder (~> 3.0.0)
|
29
|
-
i18n (~> 0.6)
|
30
|
-
activerecord (3.1.1)
|
31
|
-
activemodel (= 3.1.1)
|
32
|
-
activesupport (= 3.1.1)
|
33
|
-
arel (~> 2.2.1)
|
34
|
-
tzinfo (~> 0.3.29)
|
35
|
-
activeresource (3.1.1)
|
36
|
-
activemodel (= 3.1.1)
|
37
|
-
activesupport (= 3.1.1)
|
38
|
-
activesupport (3.1.1)
|
39
|
-
multi_json (~> 1.0)
|
40
|
-
arel (2.2.1)
|
41
|
-
builder (3.0.0)
|
42
|
-
coderay (0.9.8)
|
43
|
-
coffee-script (2.2.0)
|
44
|
-
coffee-script-source
|
45
|
-
execjs
|
46
|
-
coffee-script-source (1.1.3)
|
47
|
-
diff-lcs (1.1.3)
|
48
|
-
erubis (2.7.0)
|
49
|
-
execjs (1.2.9)
|
50
|
-
multi_json (~> 1.0)
|
51
|
-
haml (3.1.3)
|
52
|
-
hike (1.2.1)
|
53
|
-
i18n (0.6.0)
|
54
|
-
jasminerice (0.0.8)
|
55
|
-
haml
|
56
|
-
jquery-rails (1.0.16)
|
57
|
-
railties (~> 3.0)
|
58
|
-
thor (~> 0.14)
|
59
|
-
json (1.6.1)
|
60
|
-
mail (2.3.0)
|
61
|
-
i18n (>= 0.4.0)
|
62
|
-
mime-types (~> 1.16)
|
63
|
-
treetop (~> 1.4.8)
|
64
|
-
method_source (0.6.7)
|
65
|
-
ruby_parser (>= 2.3.1)
|
66
|
-
mime-types (1.17.2)
|
67
|
-
multi_json (1.0.3)
|
68
|
-
polyglot (0.3.3)
|
69
|
-
pry (0.9.7.4)
|
70
|
-
coderay (~> 0.9.8)
|
71
|
-
method_source (~> 0.6.7)
|
72
|
-
ruby_parser (>= 2.3.1)
|
73
|
-
slop (~> 2.1.0)
|
74
|
-
rack (1.3.5)
|
75
|
-
rack-cache (1.1)
|
76
|
-
rack (>= 0.4)
|
77
|
-
rack-mount (0.8.3)
|
78
|
-
rack (>= 1.0.0)
|
79
|
-
rack-ssl (1.3.2)
|
80
|
-
rack
|
81
|
-
rack-test (0.6.1)
|
82
|
-
rack (>= 1.0)
|
83
|
-
rails (3.1.1)
|
84
|
-
actionmailer (= 3.1.1)
|
85
|
-
actionpack (= 3.1.1)
|
86
|
-
activerecord (= 3.1.1)
|
87
|
-
activeresource (= 3.1.1)
|
88
|
-
activesupport (= 3.1.1)
|
89
|
-
bundler (~> 1.0)
|
90
|
-
railties (= 3.1.1)
|
91
|
-
railties (3.1.1)
|
92
|
-
actionpack (= 3.1.1)
|
93
|
-
activesupport (= 3.1.1)
|
94
|
-
rack-ssl (~> 1.3.2)
|
95
|
-
rake (>= 0.8.7)
|
96
|
-
rdoc (~> 3.4)
|
97
|
-
thor (~> 0.14.6)
|
98
|
-
rake (0.9.2.2)
|
99
|
-
rdoc (3.11)
|
100
|
-
json (~> 1.4)
|
101
|
-
rspec (2.7.0)
|
102
|
-
rspec-core (~> 2.7.0)
|
103
|
-
rspec-expectations (~> 2.7.0)
|
104
|
-
rspec-mocks (~> 2.7.0)
|
105
|
-
rspec-core (2.7.1)
|
106
|
-
rspec-expectations (2.7.0)
|
107
|
-
diff-lcs (~> 1.1.2)
|
108
|
-
rspec-mocks (2.7.0)
|
109
|
-
ruby_parser (2.3.1)
|
110
|
-
sexp_processor (~> 3.0)
|
111
|
-
sexp_processor (3.0.8)
|
112
|
-
slop (2.1.0)
|
113
|
-
sprockets (2.0.3)
|
114
|
-
hike (~> 1.2)
|
115
|
-
rack (~> 1.0)
|
116
|
-
tilt (~> 1.1, != 1.3.0)
|
117
|
-
thor (0.14.6)
|
118
|
-
tilt (1.3.3)
|
119
|
-
treetop (1.4.10)
|
120
|
-
polyglot
|
121
|
-
polyglot (>= 0.3.1)
|
122
|
-
tzinfo (0.3.31)
|
123
|
-
|
124
|
-
PLATFORMS
|
125
|
-
ruby
|
126
|
-
|
127
|
-
DEPENDENCIES
|
128
|
-
coffee-script
|
129
|
-
jasminerice
|
130
|
-
jquery-rails
|
131
|
-
knockout-rails!
|
132
|
-
pry
|
133
|
-
rails (>= 3.1.1)
|
134
|
-
rspec
|
@@ -1 +0,0 @@
|
|
1
|
-
#TODO: Add additional bindings
|
@@ -1 +0,0 @@
|
|
1
|
-
# TODO: add additional observers
|