Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

added new bindings

  • Loading branch information...
commit 2496c6c0c6e1366dfbf1875f97e311d918479402 1 parent f7dd4aa
@dnagir authored
View
1  .gitignore
@@ -6,3 +6,4 @@ spec/dummy/db/*.sqlite3
spec/dummy/log/*.log
spec/dummy/tmp/
spec/dummy/public/assets/
+Gemfile.lock
View
4 Gemfile
@@ -10,3 +10,7 @@ group :development, :test do
end
gem 'jquery-rails' # For the dummy app
+
+# Bindings assets
+gem 'pakunok' # Provides some assets for the bindings
+gem 'ios-checkboxes'
View
8 Gemfile.lock
@@ -51,6 +51,8 @@ GEM
haml (3.1.3)
hike (1.2.1)
i18n (0.6.0)
+ ios-checkboxes (0.1.0)
+ railties (~> 3.1)
jasminerice (0.0.8)
haml
jquery-rails (1.0.16)
@@ -65,6 +67,10 @@ GEM
ruby_parser (>= 2.3.1)
mime-types (1.17.2)
multi_json (1.0.3)
+ pakunok (0.0.3)
+ execjs
+ rails (>= 3.1.0)
+ sprockets (>= 2.0.0)
polyglot (0.3.3)
pry (0.9.7.4)
coderay (~> 0.9.8)
@@ -126,9 +132,11 @@ PLATFORMS
DEPENDENCIES
coffee-script
+ ios-checkboxes
jasminerice
jquery-rails
knockout-rails!
+ pakunok
pry
rails (>= 3.1.1)
rspec
View
26 lib/assets/javascripts/knockout/bindings/autosave.js.coffee
@@ -0,0 +1,26 @@
+valOrDefault = (val, def) ->
+ if val?
+ ko.utils.unwrapObservable val
+ else
+ def
+
+ko.bindingHandlers.autosave =
+ init: (element, valueAccessor, allBindingsAccessor, viewModel) ->
+ form = $(element)
+ form.submit (e) -> e.preventDefault()
+
+ options = valueAccessor()
+ [ifYes, ifNo, model] = [options.when, options.unless, options.model]
+
+ model = options unless ifYes? or ifNo?
+
+ throw "Pls provide either MODEL object or: {model: yourModel, when: optionalTrueCondition, unless: optionalFalseCondition}" unless model.save
+
+ doSave = model.save.debounce(500) # Not too fast
+
+ # subscribe to all notifications of all the observable fields of the model
+ observables = Object.keys(model).filter((x)->ko.isObservable model[x]).map (x)->model[x]
+ observables.forEach (o) -> o.subscribe ->
+ ye = valOrDefault ifYes, true
+ na = valOrDefault ifNo, false
+ doSave() if ye and not na
View
21 lib/assets/javascripts/knockout/bindings/color.js.coffee
@@ -0,0 +1,21 @@
+#= require pakunok/colorpicker
+
+valOf = (va)-> ko.utils.unwrapObservable(va()) or ''
+
+picker =
+ init: (element, valueAccessor) ->
+ val = valOf valueAccessor
+ el = $(element)
+ el.addClass('color').css('backgroundColor', val).ColorPicker
+ color: val
+ onChange: (hsb, hex, rgb) ->
+ newVal = "rgb(#{rgb.r}, #{rgb.g}, #{rgb.b})"
+ valueAccessor() newVal
+
+ update: (element, valueAccessor) ->
+ newValue = valOf valueAccessor
+ $(element).css('backgroundColor', newValue)
+
+
+
+ko.bindingHandlers.color = picker
View
44 lib/assets/javascripts/knockout/bindings/inplace.js.coffee
@@ -0,0 +1,44 @@
+showInput = (element, showOrHide, valueAccessor) ->
+ el = $(element)
+ editable = el.next()
+ button = editable.next()
+ editable.toggle(!showOrHide)
+ el.toggle(showOrHide)
+ val = ko.utils.unwrapObservable valueAccessor()
+ if showOrHide
+ button.text 'Done'
+ el.val val
+ else
+ button.text 'Edit'
+ editable.text val
+
+
+toggle = (element, valueAccessor) ->
+ showingInput = not editing(element)
+ showInput element, showingInput, valueAccessor
+
+updateValue = (element, valueAccessor) ->
+ valueAccessor()( $(element).val() )
+
+editing = (element) -> $(element).is(':visible')
+
+ko.bindingHandlers.inplace =
+ init: (element, valueAccessor) ->
+ val = ko.utils.unwrapObservable valueAccessor()
+ editable = $("<span class='editable-content' />").insertAfter(element)
+ button = $("<a href='#' class='inline-button'>Edit</a>").insertAfter editable
+ showInput element, false, valueAccessor
+
+ button.closest('form').submit ->
+ updateValue element, valueAccessor if editing(element)
+ showInput element, false, valueAccessor
+ button.click (e) ->
+ e.preventDefault()
+ if editing element
+ updateValue element, valueAccessor
+ else
+ toggle element, valueAccessor
+
+
+ update: (element, valueAccessor) ->
+ showInput element, false, valueAccessor
View
21 lib/assets/javascripts/knockout/bindings/onoff.js.coffee
@@ -0,0 +1,21 @@
+#= require ios-checkboxes
+
+ko.bindingHandlers.onoff =
+ init: (element, valueAccessor, allBindingsAccessor) ->
+
+ initialValue = ko.utils.unwrapObservable valueAccessor()
+ $(element).prop('checked', initialValue).iphoneStyle
+ handleMargin: 0
+ containerRadius: 0
+ resizeHandle: false
+ resizeContainer: false
+ checkedLabel: 'On'
+ uncheckedLabel: 'Off'
+ onChange: (el, checked) ->
+ writer = valueAccessor()
+ writer checked
+
+ update: (element, valueAccessor) ->
+ el = $(element)
+ val = ko.utils.unwrapObservable valueAccessor()
+ el.prop('checked', val)
View
78 spec/javascripts/knockout/bindings/autosave_spec.js.coffee
@@ -0,0 +1,78 @@
+#= require knockout/bindings/autosave
+
+class Page extends ko.Model
+ @configure 'page'
+
+describe "AutoSave", ->
+ beforeEach ->
+ jasmine.Ajax.useMock()
+ jasmine.Clock.useMock()
+
+ prepare = (bindings, viewModel) ->
+ page = new Page { name: 'Home' }
+ setFixtures "<form id='autosave' data-bind='autosave: #{bindings}' />"
+ form = $("#autosave")[0]
+ viewModel = if viewModel
+ ko.utils.extend viewModel, {page: page}
+ else
+ {page: page}
+ ko.applyBindings viewModel, form
+ page
+
+
+
+ it "should call 'save' when property changes and use delay", ->
+ model = prepare "page"
+
+ model.name 'Index'
+ jasmine.Clock.tick 100
+ expect(mostRecentAjaxRequest()).toBeFalsy()
+
+ jasmine.Clock.tick 5000
+ expect(mostRecentAjaxRequest()).toBeTruthy()
+
+
+ it "should not save when 'when' condition is falsy", ->
+ model = prepare "{model: page, when: shouldSave}", {shouldSave: false}
+
+ model.name 'Index'
+ jasmine.Clock.tick 5000
+ expect(mostRecentAjaxRequest()).toBeFalsy()
+
+ it "should save when 'when' condition is truthy", ->
+ model = prepare "{model: page, when: shouldSave}", shouldSave: ko.observable(true)
+ model.name 'Index'
+ jasmine.Clock.tick 5000
+ expect(mostRecentAjaxRequest()).toBeTruthy()
+
+ it "should save when 'unless' condition is falsy", ->
+ model = prepare "{model: page, unless: dontSave}", dontSave: false
+ model.name 'Index'
+ jasmine.Clock.tick 5000
+ expect(mostRecentAjaxRequest()).toBeTruthy()
+
+ it "should not save when 'unless' condition is truthy", ->
+ model = prepare "{model: page, unless: dontSave}", dontSave: true
+ model.name 'Index'
+ jasmine.Clock.tick 5000
+ expect(mostRecentAjaxRequest()).toBeFalsy()
+
+ it "should save with when=true, unless=false", ->
+ model = prepare "{model: page, when: shouldSave, unless: dontSave}", shouldSave: true, dontSave: false
+ model.name 'Index'
+ jasmine.Clock.tick 5000
+ expect(mostRecentAjaxRequest()).toBeTruthy()
+
+ it "should not save with when=false, unless=false", ->
+ model = prepare "{model: page, when: shouldSave, unless: dontSave}", shouldSave: false, dontSave: false
+ model.name 'Index'
+ jasmine.Clock.tick 5000
+ expect(mostRecentAjaxRequest()).toBeFalsy()
+
+
+ it "should not save with when=true, unless=true", ->
+ model = prepare "{model: page, when: shouldSave, unless: dontSave}", shouldSave: true, dontSave: true
+ model.name 'Index'
+ jasmine.Clock.tick 5000
+ expect(mostRecentAjaxRequest()).toBeFalsy()
+
View
35 spec/javascripts/knockout/bindings/color_spec.js.coffee
@@ -0,0 +1,35 @@
+#= require knockout/bindings/color
+
+describe "Color picker", ->
+ colorise = (color)->
+ setFixtures "<div id='color' data-bind='color: color' />"
+ el = $ '#color'
+ ko.applyBindings {color: color or ko.observable("rgb(1, 2, 3)")}, el[0]
+ el
+
+ afterEach ->
+ # It adds itself to the body, so is outisde of the fixure
+ $(".colorpicker").remove()
+
+ it "should set the initial background color", ->
+ el = colorise()
+ expect(el.css 'backgroundColor').toBe 'rgb(1, 2, 3)'
+
+ it "should add 'color' class to element", ->
+ el = colorise()
+ expect(el).toBe ".color"
+
+
+ it "should reflect the changed color in the UI", ->
+ color = ko.observable "rgb(1, 2, 3)"
+ el = colorise color
+ color "rgb(4, 5, 6)" # Modify the color here
+ expect(el.css 'backgroundColor').toBe 'rgb(4, 5, 6)'
+
+
+ it "should update the value when user changes the color", ->
+ color = ko.observable "rgb(1, 2, 3)"
+ el = colorise color
+ $(".colorpicker").data('colorpicker').onChange "hsb", "hex", {r: 4, g: 5, b: 6}
+ expect(color()).toBe 'rgb(4, 5, 6)'
+
View
42 spec/javascripts/knockout/bindings/inplace_spec.js.coffee
@@ -0,0 +1,42 @@
+#= require knockout/bindings/inplace
+
+describe "In-Place edit", ->
+
+ inplacify = (val) ->
+ setFixtures "<input id='el' data-bind='inplace: val' />"
+ el = $('#el')
+ ko.applyBindings { val: val or ko.observable() }, @el[0]
+ el
+
+ it "should hide input initially", ->
+ el = inplacify()
+ expect(el).toBeHidden()
+
+ it "should show the current value", ->
+ val = ko.observable 'hi there'
+ el = inplacify val
+ expect(el.parent().find '.editable-content').toHaveText 'hi there'
+
+ it "should create an Edit link", ->
+ el = inplacify()
+ expect(el.parent()).toContain "a.inline-button"
+
+ it "should show input when clicking the Edit link", ->
+ el = inplacify()
+ el.parent().find('a.inline-button').click()
+ expect(el).toBeVisible()
+
+ it "should not update the value on 'change' event", ->
+ val = ko.observable 'Initial'
+ el = inplacify val
+ el.val 'from dom'
+ el.change()
+ expect(val()).toBe 'Initial'
+
+ it "should update the value clicking Done", ->
+ val = ko.observable 'initial'
+ el = inplacify val
+ el.parent().find('.inline-button').click() # Edit
+ el.val('updated')
+ el.parent().find('.inline-button').click() # Done
+ expect( val() ).toBe 'updated'
View
2  spec/javascripts/knockout/bindings_spec.js.coffee
@@ -1,2 +0,0 @@
-describe "bindings", ->
- it "coming soon"
View
3  spec/javascripts/knockout/observables_spec.js.coffee
@@ -1,3 +0,0 @@
-describe "observables", ->
-
- it "coming soon"
View
3  spec/javascripts/spec.js.coffee
@@ -1,3 +1,6 @@
#=require knockout
#=require_tree ./support
#=require_tree ./
+
+beforeEach ->
+ clearAjaxRequests()
Please sign in to comment.
Something went wrong with that request. Please try again.