diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..06258e2 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +*.js -crlf +*.coffee -crlf \ No newline at end of file diff --git a/.gitignore b/.gitignore index 7482412..5ddc398 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ node_modules -spec/*.spec.js \ No newline at end of file +spec/*.spec.js +.c9 \ No newline at end of file diff --git a/dist/backbone.eventstreams.js b/dist/backbone.eventstreams.js index b89f50f..0b7698c 100644 --- a/dist/backbone.eventstreams.js +++ b/dist/backbone.eventstreams.js @@ -1,79 +1,121 @@ (function() { - var __slice = [].slice; + var Backbone, Bacon, init, + __slice = [].slice; - Backbone.EventStream = { - listenToEventStream: function(eventTarget, eventName, eventTransformer) { - var listener; - if (eventTransformer == null) { - eventTransformer = _.identity; + init = function(Bacon, Backbone) { + var ReactiveView, _undelegate; + Backbone.EventStream = { + listenToEventStream: function(eventTarget, eventName, eventTransformer) { + var listener; + if (eventTransformer == null) { + eventTransformer = _.identity; + } + listener = this; + return Bacon.fromBinder(function(sink) { + var handler, unbind; + handler = function() { + var args, reply; + args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + reply = sink(new Bacon.Next(eventTransformer.apply(null, args))); + if (reply === Bacon.noMore) { + return unbind(); + } + }; + unbind = function() { + return listener.stopListening(eventTarget, eventName, handler); + }; + listener.listenTo(eventTarget, eventName, handler); + return unbind; + }); + }, + asEventStream: function(eventName, eventTransformer) { + var eventTarget; + if (eventTransformer == null) { + eventTransformer = _.identity; + } + eventTarget = this; + return Bacon.fromBinder(function(sink) { + var handler, unbind; + handler = function() { + var args, reply; + args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + reply = sink(new Bacon.Next(eventTransformer.apply(null, args))); + if (reply === Bacon.noMore) { + return unbind(); + } + }; + unbind = function() { + return eventTarget.off(eventName, handler); + }; + eventTarget.on(eventName, handler, this); + return unbind; + }); } - listener = this; - return new Bacon.EventStream(function(sink) { - var handler, unbind; - handler = function() { - var args, reply; - args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; - reply = sink(new Bacon.Next(eventTransformer.apply(null, args))); - if (reply === Bacon.noMore) { - return unbind(); - } + }; + _.extend(Backbone, Backbone.EventStream); + _.extend(Backbone.Model.prototype, Backbone.EventStream); + _.extend(Backbone.Collection.prototype, Backbone.EventStream); + _.extend(Backbone.Router.prototype, Backbone.EventStream); + _.extend(Backbone.History.prototype, Backbone.EventStream); + _.extend(Backbone.View.prototype, Backbone.EventStream); + Backbone.BaconProperty = { + toModel: function() { + var handler, model; + model = new Backbone.Model(this.take(1)); + handler = function(value) { + return model.set(value); }; - unbind = function() { - return listener.stopListening(eventTarget, eventName, handler); - }; - listener.listenTo(eventTarget, eventName, handler); - return unbind; - }); - }, - asEventStream: function(eventName, eventTransformer) { - var eventTarget; - if (eventTransformer == null) { - eventTransformer = _.identity; + this.onValue(handler); + return model; } - eventTarget = this; - return new Bacon.EventStream(function(sink) { - var handler, unbind; - handler = function() { - var args, reply; - args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; - reply = sink(new Bacon.Next(eventTransformer.apply(null, args))); - if (reply === Bacon.noMore) { - return unbind(); - } - }; - unbind = function() { - return eventTarget.off(eventName, handler); - }; - eventTarget.on(eventName, handler, this); - return unbind; - }); - } - }; - - _.extend(Backbone, Backbone.EventStream); - - _.extend(Backbone.Model.prototype, Backbone.EventStream); - - _.extend(Backbone.Collection.prototype, Backbone.EventStream); - - _.extend(Backbone.Router.prototype, Backbone.EventStream); - - _.extend(Backbone.History.prototype, Backbone.EventStream); - - _.extend(Backbone.View.prototype, Backbone.EventStream); - - Backbone.BaconProperty = { - toModel: function() { - var handler, model; - model = new Backbone.Model(this.take(1)); - handler = function(value) { - return model.set(value); + }; + _.extend(Bacon.Property.prototype, Backbone.BaconProperty); + (function(proto) { + return proto.matches = proto.matchesSelector = proto.matches || proto.matchesSelector || proto.webkitMatchesSelector || proto.mozMatchesSelector || proto.msMatchesSelector || proto.oMatchesSelector || function(selector) { + var i, nodes; + nodes = (this.parentNode || this.document).querySelectorAll(selector); + i = -1; + while (nodes[++i] && nodes[i] !== this) {} + return !!nodes[i]; }; - this.onValue(handler); - return model; - } + })(Element.prototype); + _undelegate = Backbone.View.prototype.undelegateEvents; + ReactiveView = { + onEvent: function(eventName, selector, eventTransformer) { + var stream, _ref; + if ((_ref = this.bus) == null) { + this.bus = new Bacon.Bus(); + } + stream = this.$el.asEventStream(eventName, selector, eventTransformer); + this.bus.plug(stream); + return this.bus.filter(function(x) { + return x instanceof $.Event && x.type === eventName && (!(selector != null) || x.currentTarget.matches(selector)); + }); + }, + undelegateEvents: function() { + var args, _ref; + args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + _undelegate.apply(this, args); + if ((_ref = this.bus) != null) { + _ref.end(); + } + return this; + } + }; + _.extend(Backbone.View.prototype, ReactiveView); + return Backbone; }; - _.extend(Bacon.Property.prototype, Backbone.BaconProperty); + if (typeof module !== "undefined" && module !== null) { + Bacon = require("baconjs"); + Backbone = require("backbone"); + module.exports = init(Bacon, Backbone); + } else { + if (typeof define === "function" && define.amd) { + define(["bacon", "backbone"], init); + } else { + init(this.Bacon, this.Backbone); + } + } }).call(this); diff --git a/dist/backbone.eventstreams.min.js b/dist/backbone.eventstreams.min.js index fce2f90..e0e83c1 100644 --- a/dist/backbone.eventstreams.min.js +++ b/dist/backbone.eventstreams.min.js @@ -1,4 +1,4 @@ -/*! Backbone.EventStreams - v0.1.0 - 2013-01-31 +/*! Backbone.EventStreams - v0.1.0 - 2015-06-03 * https://github.com/pyykkis/Backbone.EventStreams -* Copyright (c) 2013 Jarno Keskikangas ; Licensed MIT */ -(function(){var e=[].slice;Backbone.EventStream={listenToEventStream:function(t,n,r){var i;return r==null&&(r=_.identity),i=this,new Bacon.EventStream(function(s){var o,u;return o=function(){var t,n;t=1<=arguments.length?e.call(arguments,0):[],n=s(new Bacon.Next(r.apply(null,t)));if(n===Bacon.noMore)return u()},u=function(){return i.stopListening(t,n,o)},i.listenTo(t,n,o),u})},asEventStream:function(t,n){var r;return n==null&&(n=_.identity),r=this,new Bacon.EventStream(function(i){var s,o;return s=function(){var t,r;t=1<=arguments.length?e.call(arguments,0):[],r=i(new Bacon.Next(n.apply(null,t)));if(r===Bacon.noMore)return o()},o=function(){return r.off(t,s)},r.on(t,s,this),o})}},_.extend(Backbone,Backbone.EventStream),_.extend(Backbone.Model.prototype,Backbone.EventStream),_.extend(Backbone.Collection.prototype,Backbone.EventStream),_.extend(Backbone.Router.prototype,Backbone.EventStream),_.extend(Backbone.History.prototype,Backbone.EventStream),_.extend(Backbone.View.prototype,Backbone.EventStream)}).call(this); \ No newline at end of file +* Copyright (c) 2015 Jarno Keskikangas ; Licensed MIT */ +(function(){var e,t,n,r=[].slice;n=function(e,t){var n,i;return t.EventStream={listenToEventStream:function(t,n,i){var s;return i==null&&(i=_.identity),s=this,e.fromBinder(function(o){var u,a;return u=function(){var t,n;t=1<=arguments.length?r.call(arguments,0):[],n=o(new e.Next(i.apply(null,t)));if(n===e.noMore)return a()},a=function(){return s.stopListening(t,n,u)},s.listenTo(t,n,u),a})},asEventStream:function(t,n){var i;return n==null&&(n=_.identity),i=this,e.fromBinder(function(s){var o,u;return o=function(){var t,i;t=1<=arguments.length?r.call(arguments,0):[],i=s(new e.Next(n.apply(null,t)));if(i===e.noMore)return u()},u=function(){return i.off(t,o)},i.on(t,o,this),u})}},_.extend(t,t.EventStream),_.extend(t.Model.prototype,t.EventStream),_.extend(t.Collection.prototype,t.EventStream),_.extend(t.Router.prototype,t.EventStream),_.extend(t.History.prototype,t.EventStream),_.extend(t.View.prototype,t.EventStream),t.BaconProperty={toModel:function(){var e,n;return n=new t.Model(this.take(1)),e=function(e){return n.set(e)},this.onValue(e),n}},_.extend(e.Property.prototype,t.BaconProperty),function(e){return e.matches=e.matchesSelector=e.matches||e.matchesSelector||e.webkitMatchesSelector||e.mozMatchesSelector||e.msMatchesSelector||e.oMatchesSelector||function(e){var t,n;n=(this.parentNode||this.document).querySelectorAll(e),t=-1;while(n[++t]&&n[t]!==this);return!!n[t]}}(Element.prototype),i=t.View.prototype.undelegateEvents,n={onEvent:function(t,n,r){var i,s;return(s=this.bus)==null&&(this.bus=new e.Bus),i=this.$el.asEventStream(t,n,r),this.bus.plug(i),this.bus.filter(function(e){return e instanceof $.Event&&e.type===t&&(n==null||e.currentTarget.matches(n))})},undelegateEvents:function(){var e,t;return e=1<=arguments.length?r.call(arguments,0):[],i.apply(this,e),(t=this.bus)!=null&&t.end(),this}},_.extend(t.View.prototype,n),t},typeof module!="undefined"&&module!==null?(t=require("baconjs"),e=require("backbone"),module.exports=n(t,e)):typeof define=="function"&&define.amd?define(["bacon","backbone"],n):n(this.Bacon,this.Backbone)}).call(this); \ No newline at end of file diff --git a/grunt.js b/grunt.js index 5f4ef0e..f8caef2 100644 --- a/grunt.js +++ b/grunt.js @@ -51,3 +51,4 @@ module.exports = function(grunt) { grunt.registerTask('test', ['coffee', 'jasmine']); }; + diff --git a/package.json b/package.json index 1d28239..eecad14 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "Backbone.EventStreams", "version": "0.1.0", - "main": "dist/bacbone.eventstreams.js", + "main": "dist/backbone.eventstreams.js", "description": "Backbone events as Bacon.js EventStreams", "homepage": "https://github.com/pyykkis/Backbone.EventStreams", "repository": { diff --git a/src/backbone.eventstreams.coffee b/src/backbone.eventstreams.coffee index c282a31..915fbbb 100644 --- a/src/backbone.eventstreams.coffee +++ b/src/backbone.eventstreams.coffee @@ -1,42 +1,88 @@ -Backbone.EventStream = - listenToEventStream: (eventTarget, eventName, eventTransformer = _.identity) -> - listener = this - new Bacon.EventStream (sink) -> - handler = (args...) -> - reply = sink(new Bacon.Next(eventTransformer args...)) - if reply == Bacon.noMore - unbind() - - unbind = -> listener.stopListening(eventTarget, eventName, handler) - listener.listenTo(eventTarget, eventName, handler) - unbind - - asEventStream: (eventName, eventTransformer = _.identity) -> - eventTarget = this - new Bacon.EventStream (sink) -> - handler = (args...) -> - reply = sink(new Bacon.Next(eventTransformer args...)) - if reply == Bacon.noMore - unbind() - - unbind = -> eventTarget.off(eventName, handler) - eventTarget.on(eventName, handler, this) - unbind - -_.extend Backbone, Backbone.EventStream -_.extend Backbone.Model.prototype, Backbone.EventStream -_.extend Backbone.Collection.prototype, Backbone.EventStream -_.extend Backbone.Router.prototype, Backbone.EventStream -_.extend Backbone.History.prototype, Backbone.EventStream -_.extend Backbone.View.prototype, Backbone.EventStream - -Backbone.BaconProperty = - toModel: -> - model = new Backbone.Model(this.take(1)) - handler = (value) -> - model.set value - this.onValue(handler) - model - - -_.extend Bacon.Property.prototype, Backbone.BaconProperty \ No newline at end of file +init = (Bacon, Backbone) -> + Backbone.EventStream = + listenToEventStream: (eventTarget, eventName, eventTransformer = _.identity) -> + listener = this + Bacon.fromBinder (sink) -> + handler = (args...) -> + reply = sink(new Bacon.Next(eventTransformer args...)) + if reply == Bacon.noMore + unbind() + + unbind = -> listener.stopListening(eventTarget, eventName, handler) + listener.listenTo(eventTarget, eventName, handler) + unbind + + asEventStream: (eventName, eventTransformer = _.identity) -> + eventTarget = this + Bacon.fromBinder (sink) -> + handler = (args...) -> + reply = sink(new Bacon.Next(eventTransformer args...)) + if reply == Bacon.noMore + unbind() + + unbind = -> eventTarget.off(eventName, handler) + eventTarget.on(eventName, handler, this) + unbind + + _.extend Backbone, Backbone.EventStream + _.extend Backbone.Model.prototype, Backbone.EventStream + _.extend Backbone.Collection.prototype, Backbone.EventStream + _.extend Backbone.Router.prototype, Backbone.EventStream + _.extend Backbone.History.prototype, Backbone.EventStream + _.extend Backbone.View.prototype, Backbone.EventStream + + Backbone.BaconProperty = + toModel: -> + model = new Backbone.Model(this.take(1)) + handler = (value) -> + model.set value + this.onValue(handler) + model + + + _.extend Bacon.Property.prototype, Backbone.BaconProperty + + ((proto) -> + proto.matches = proto.matchesSelector = proto.matches || + proto.matchesSelector || + proto.webkitMatchesSelector || + proto.mozMatchesSelector || + proto.msMatchesSelector || + proto.oMatchesSelector || + (selector) -> + nodes = (@parentNode || @document).querySelectorAll(selector) + i = -1 + while (nodes[++i] && nodes[i] isnt @) then + !!nodes[i] + )(Element::) + + + _undelegate = Backbone.View::undelegateEvents + + ReactiveView = + onEvent: (eventName, selector, eventTransformer) -> + @bus ?= new Bacon.Bus() + stream = @$el.asEventStream(eventName, selector, eventTransformer) + @bus.plug stream + @bus.filter (x) -> + x instanceof $.Event && + x.type is eventName && + (!selector? || x.currentTarget.matches(selector)) + + undelegateEvents: (args...) -> + _undelegate.apply(@, args) + @bus?.end() + @ + + _.extend Backbone.View.prototype, ReactiveView + Backbone + +if module? + Bacon = require("baconjs") + Backbone = require("backbone") + module.exports = init(Bacon, Backbone) +else + if typeof define == "function" and define.amd + define ["bacon", "backbone"], init + else + init(this.Bacon, this.Backbone) \ No newline at end of file