Created
February 17, 2011 19:17
-
-
Save thelinuxlich/832422 to your computer and use it in GitHub Desktop.
Knockout.live.plugin.coffee
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
### | |
Knockout Live plugin | |
http://github.com/thelinuxlich/knockout.live.plugin | |
Copyright 2011, Alisson Cavalcante Agiani | |
Licensed under the MIT license. | |
http://github.com/thelinuxlich/knockout.live.plugin/MIT-LICENSE.txt | |
Date: Mon Feb 01 09:00:29 2011 -0300 | |
### | |
# isArray helper | |
ko.utils.isArray = (obj) -> toString.call(obj) is "[object Array]" | |
# Syntactic sugar | |
KO = (value) -> | |
if ko.utils.isArray(value) is true | |
ko.observableArray value | |
else if typeof value is "function" | |
if arguments.length > 1 | |
ko.dependentObservable value,arguments[1] | |
else | |
return ko.dependentObservable(value) | |
else | |
ko.observable value | |
# Cache to fasten varname searches | |
ko.utils.cachedVarnameReferences = {} | |
# Wraps socket.io client and messaging for knockout observables | |
ko.utils.socketConnect = (address,port) -> | |
ko.socket = new io.Socket(address, {port: port, rememberTransport: false}) | |
ko.socket.connect() | |
ko.socket.on 'message', (obj) -> | |
if obj.msg.varname in ko.utils.cachedVarnameReferences | |
temporaryViewModelField = ko.utils.cachedVarnameReferences[obj.msg.varname] | |
else | |
obj_tree = obj.msg.varname.split "." | |
temporaryViewModelField = window[obj_tree.splice(0,1)] | |
for i in [0..obj_tree.length -1] | |
temporaryViewModelField = temporaryViewModelField[obj_tree[i]] | |
if i + 1 < obj_tree.length | |
if ko.isObservable(temporaryViewModelField) | |
temporaryViewModelField = temporaryViewModelField() | |
ko.utils.cachedVarnameReferences[obj.msg.varname] = temporaryViewModelField | |
temporaryViewModelField({koValue: obj.msg.value,sync: false}) | |
# Custom writable dependent observable that handles synchronizing with node server | |
Function.prototype.live = (varname) -> | |
underlyingObservable = @ | |
obs = ko.dependentObservable | |
read: underlyingObservable | |
write: (value) -> | |
if typeof value is "object" and value.sync is false and value.koValue isnt undefined | |
underlyingObservable value.koValue | |
else if typeof value is "object" and value.koValue isnt undefined | |
underlyingObservable value.koValue | |
ko.socket.send {varname: varname,value: value.koValue} | |
else | |
underlyingObservable value | |
ko.socket.send {varname: varname,value: value} | |
# This is needed for observableArrays | |
if ko.utils.isArray(underlyingObservable()) is true | |
ko.utils.arrayForEach ["pop", "push", "reverse", "shift", "sort", "splice", "unshift"], (methodName) -> | |
obs[methodName] = -> | |
methodCallResult = underlyingObservable[methodName].apply underlyingObservable(), arguments | |
ko.socket.send {varname: varname,value: underlyingObservable()} | |
underlyingObservable.valueHasMutated() | |
methodCallResult | |
obs.slice = -> underlyingObservable[methodName].apply underlyingObservable(), arguments | |
obs.remove = (valueOrPredicate) -> | |
underlyingArray = underlyingObservable() | |
remainingValues = [] | |
removedValues = [] | |
predicate = if typeof valueOrPredicate is "function" then valueOrPredicate else (value) -> value is valueOrPredicate | |
for i in [0..underlyingArray.length -1] | |
value = underlyingArray[i] | |
if !predicate(value) | |
remainingValues.push value | |
else | |
removedValues.push value | |
underlyingObservable remainingValues | |
ko.socket.send {varname: varname,value: underlyingObservable()} | |
removedValues | |
obs.removeAll = (arrayOfValues) -> | |
# If you passed zero args, we remove everything | |
if arrayOfValues is undefined | |
allValues = underlyingObservable() | |
underlyingObservable [] | |
ko.socket.send {varname: varname,value: underlyingObservable()} | |
allValues | |
# If you passed an arg, we interpret it as an array of entries to remove | |
if !arrayOfValues | |
return [] | |
elements = underlyingObservable.remove (value) -> ko.utils.arrayIndexOf(arrayOfValues, value) >= 0 | |
ko.socket.send {varname: varname,value: underlyingObservable()} | |
elements | |
obs.destroy = (valueOrPredicate) -> | |
predicate = if typeof valueOrPredicate is "function" then valueOrPredicate else (value) -> value is valueOrPredicate | |
for i in [underlyingObservable().length - 1..0] | |
value = underlyingObservable()[i] | |
if predicate(value) | |
underlyingObservable()[i]["_destroy"] = true | |
underlyingObservable.valueHasMutated() | |
ko.socket.send {varname: varname,value: underlyingObservable()} | |
obs.destroyAll = (arrayOfValues) -> | |
# If you passed zero args, we destroy everything | |
if arrayOfValues is undefined | |
result = underlyingObservable.destroy -> true | |
ko.socket.send {varname: varname,value: underlyingObservable()} | |
return result | |
# If you passed an arg, we interpret it as an array of entries to destroy | |
if !arrayOfValues | |
return [] | |
result = underlyingObservable.destroy (value) -> | |
ko.utils.arrayIndexOf(arrayOfValues, value) >= 0 | |
ko.socket.send {varname: varname,value: underlyingObservable()} | |
result | |
obs.indexOf = (item) -> ko.utils.arrayIndexOf(underlyingObservable(), item) | |
obs.replace = (oldItem, newItem) -> | |
index = underlyingObservable.indexOf(oldItem) | |
if index >= 0 | |
underlyingObservable()[index] = newItem | |
underlyingObservable.valueHasMutated() | |
ko.socket.send {varname: varname,value: underlyingObservable()} | |
obs |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment