knockout-rails 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|