Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

flexify the API #40

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -8,3 +8,4 @@ browsertest/bundle.js
examples/**/components
examples/**/bower_components
scratchpad.coffee
*.map
22 changes: 22 additions & 0 deletions CHANGELOG.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
## Changelog

### 0.5.0

- remove hard dependency on jQuery (allows you to use ZeptoJS, EnderJS or a similar alternative)
- rename to *bacon-dom*
- allow init() function to be called without $ having been defined
- introduce: Bacon.$.Selector, Bacon.$.Request and Bacon.$.Promise for better customization
- requires `.toJQC(x)` method on JQC (i.e `$` selector)

- Bacon.$.Selector, Bacon.$.Request and Bacon.$.Promise can be set at any time to point to
jQuery compatible APIs (similar to jQuery $)

- Bacon.$.Selector must just point to a function which given a selector string can find an element

- Bacon.$.Request must just point to an object with a jQuery compatible `ajax` method

- Bacon.$.Promise can alternatively be set to any Promise/A+ compatible lib.
It will to use `deferred()` and fall-back to `Deferred()`
It will then use `notify()`, `resolve()` and `reject()` on the deferred

- Changed dom-inputvalue to use API such as `Bacon.$.select.value` and `Bacon.$.radioGroup.intValue`
6 changes: 3 additions & 3 deletions Gruntfile.coffee
Original file line number Diff line number Diff line change
@@ -6,12 +6,12 @@ module.exports = (grunt) ->

coffee:
compile:
files: ["dist/bacon.jquery.js": "src/bacon.jquery.coffee"]
files: ["dist/bacon-dom.js": "src/*.coffee"]

uglify:
dist:
src: "dist/bacon.jquery.js"
dest: "dist/bacon.jquery.min.js"
src: "dist/bacon-dom.js"
dest: "dist/bacon-dom.min.js"

grunt.loadNpmTasks "grunt-contrib-coffee"
grunt.loadNpmTasks "grunt-contrib-clean"
34 changes: 34 additions & 0 deletions Gruntfile.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions Gruntfile.js.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

111 changes: 70 additions & 41 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,37 @@
# bacon.jquery
# bacon-dom

A JQuery data binding library for [Bacon.js](https://github.com/baconjs/bacon.js).
A JQuery compatible (JQC) data binding library for [Bacon.js](https://github.com/baconjs/bacon.js).

Adds stuff to `Bacon.$`. Is also called BJQ.
See fx [Ender.js](http://enderjs.com/#docs) `$._select` which you can use with [qwery](https://github.com/ded/qwery)

```js
$._select = mySelectorEngine
$('#foo .bar')
```

See [example](https://github.com/ded/qwery/blob/master/src/ender.js)

[Zepto.js](http://zeptojs.com/) is another powerful jQuery alternative...

This library adds stuff to `Bacon.$`. It is also called "Baquery" (pronounced like "bakery").

Includes

- Binding the state of HTML input elements to [`Bacon.Model`](https://github.com/baconjs/bacon.model) objects that extend
the Bacon.js `Property` API by providing a bidirectional binding
- AJAX helpers. Wrap a JQuery AJAX call into an EventStream using
- AJAX helpers. Wrap a JQC AJAX call into an EventStream using
`Bacon.$.ajax("/get/stuff")`. Convert an `EventStream` of requests
into an `EventStream` of responses like `requests.ajax()`.
- FRP extensions to JQuery. Wrap JQuery events easily into an `EventStream`, as
- FRP extensions to JQC API. Wrap JQC events easily into an `EventStream`, as
in `$("body").clickE()`

This library is intended as a replacement for [Bacon.UI](https://github.com/raimohanska/Bacon.UI.js). It provides the same functionality, with the addition of two-way bound Models, model composition and lenses.
This library is a replacement for [Bacon.UI](https://github.com/raimohanska/Bacon.UI.js).

It provides the same functionality, with the addition of two-way bound Models, model composition and lenses.

## Example Applications

There are example applications in the [examples](https://github.com/baconjs/bacon.jquery/tree/master/examples) directory, each with a README.md describing how they are started.
There are example applications in the [examples](https://github.com/baconjs/bacon-dom/tree/master/examples) directory, each with a README.md describing how they are started.

Each application does essentially the same thing and the code in the example applications is essentially just this:

@@ -38,32 +51,51 @@ Each application does essentially the same thing and the code in the example app

## API

The `bacon.jquery` API consists of methods for creating a `Model` representing the
The `bacon-dom` API consists of methods for creating a `Model` representing the
state of a DOM element or a group of DOM elements. This API is published
as `Bacon.$`, and the same object is returned when using AMD or
CommonJS.

Note: The optional initiValue has now been replaced with an (optional) options hash.
Instead of `Bacon.$.textFieldValue(field, '')` use `Bacon.$.textFieldValue(field, {init: ''})`.
This is to allow for more flexibility down the line...

### Plugins


- `ajax`
- `dom-input`
- `effects`
- `events`
- `promise` (deferred)

Use `Bacon.$.plugin('dom-input', 'ajax')` to add the plugins you want to enable.

### DOM Input

`Bacon.$.addPlugin('dom-input')`

###Bacon.$.textFieldValue(field [, initValue])

Creates a `Model` for an
`<input type="text">` element, given as a JQuery object. You can optionally supply an initial value.
`<input type="text">` element, given as a JQC object. You can optionally supply an initial value.

###Bacon.$.checkBoxValue(field [, initValue])

Creates a `Model` for a
`<input type="checkbox">` element, given as a JQuery object. The value is `true` if the checkbox is checked and
`<input type="checkbox">` element, given as a JQC object. The value is `true` if the checkbox is checked and
`false` otherwise.

###Bacon.$.selectValue(field [,initValue])

Creates a `Model` for a `<select>`
element, given as a JQuery object. The value of the model corresponds to the `value` attribute of the selected `<option>` element.
element, given as a JQC object. The value of the model corresponds to the `value` attribute of the selected `<option>` element.

###Bacon.$.radioGroupValue(fields, [,initValue])

Creates a `Model` for a
group of `<input type="radio">` elements, given as a JQuery object or an Array
of jQuery objects. The value of the model corresponds to the `value` attribute
group of `<input type="radio">` elements, given as a JQC object/Array.
The value of the model corresponds to the `value` attribute
of the selected radio input element. Note that `value` is a string.

###Bacon.$.intRadioGroupValue(fields [, initValue])
@@ -73,17 +105,16 @@ Like `Bacon.$.radioGroupValue`, but for integer values.
###Bacon.$.checkBoxGroupValue(fields, [,initValue])

Creates a `Model` for a group
of `<input type="checkbox">` elements, given as a JQuery object or an Array of
jQuery objects. The value of the model is an array of the `value` attributes of
of `<input type="checkbox">` elements, given as a JQC object/Array . The value of the model is an array of the `value` attributes of
the checked checkbox input elements. For instance, if you have checkboxes and 2
of these are checked, having values `a` and `b`, the value of the Model is
`["a", "b"]`.

TODO: add HTML/JS examples

## FRP extensions to JQuery Events
## FRP extensions to JQC Events

BJQ adds methods to JQuery, for wrapping events into an `EventStream`.
BJQ adds methods to JQC, for wrapping events into an `EventStream`.

For example, to wrap click events on `<body>` into an `EventStream`, you
can
@@ -123,9 +154,9 @@ Supported methods include the following:
- loadE
- unloadE

## FRP extensions to JQuery Effects
## FRP extensions to JQC Effects

BJQ adds methods to JQuery, for performing animations and wrapping the
BJQ adds methods to JQC, for performing animations and wrapping the
result `Promise` into an `EventStream`. For example

var fadeOut = $("#thing").fadeOutE("fast")
@@ -146,7 +177,7 @@ Supported methods include the following:

## AJAX

BJQ provides helpers for JQuery AJAX. All the methods return an
BJQ provides helpers for JQC AJAX. All the methods return an
`EventStream` of AJAX results. AJAX errors are mapped into `Error`
events in the stream.

@@ -196,62 +227,60 @@ Turns your Bacon Ajax stream back to $.Deferred. It's useful if you need to prov

## Model API

All the BJQ methods, such as `textFieldValue` return a `Model` object, which is a Bacon.js `Property`, but extends that API by the following methods.

[Model API reference migrated to bacon.model](https://github.com/baconjs/bacon.model)


TODO: more
All the BJQ methods, such as `textFieldValue` return a `Model` object, which is a Bacon.js `Property`,
but extends that API with [bacon.model](https://github.com/baconjs/bacon.model) methods

## Use with AMD / RequireJS

The [requirejs example-app](https://github.com/baconjs/bacon.jquery/tree/master/examples/requirejs) uses RequireJS, like this:
The [requirejs example-app](https://github.com/baconjs/bacon-dom/tree/master/examples/requirejs) uses RequireJS, like this:

```js
require.config({
paths: {
"bacon.jquery": "../dist/bacon.jquery",
"bacon-dom": "../dist/bacon-dom",
"bacon": "components/bacon/dist/Bacon",
"jquery": "components/jquery/jquery"
}})
require(["bacon.jquery", "jquery"], function(bjq, $) {
require(["bacon-dom", "jquery"], function(bjq, $) {
left = bjq.textFieldValue($("#left"))
right = bjq.textFieldValue($("#right"))
right.bind(left)
right.assign($("#output"), "text")
})
```

The prebuilt javascript file can be found in the `dist` directory, or [here](https://raw.github.com/baconjs/bacon.jquery/master/dist/Bacon.JQuery.Bindings.js).
Note: You can substitute jquery with Zepto or any other compatible library ;)

The prebuilt javascript file can be found in the `dist` directory, or [here](https://raw.github.com/baconjs/bacon-dom/master/dist/bacon-dom.Bindings.js).

The API can be accessed using `Bacon.$` or like in the above example.

## Use without AMD

The [plain example-app](https://github.com/baconjs/bacon.jquery/tree/master/examples/plain) uses RequireJS, like this:
The [plain example-app](https://github.com/baconjs/bacon-dom/tree/master/examples/plain) uses RequireJS, like this:

So feel free to use plain old `<script>` tags to include Bacon, JQuery and BJQ.
So feel free to use plain old `<script>` tags to include Bacon, and JQC lib and BJQ.

The BJQ methods are exposed through `Bacon.$`, so you can call them as in `Bacon.$.textFieldValue(..)`.

The prebuilt javascript file can be found in the `dist` directory, or [here](https://raw.github.com/baconjs/bacon.jquery/master/dist/Bacon.JQuery.Bindings.js).
The prebuilt javascript file can be found in the `dist` directory, or [here](https://raw.github.com/baconjs/bacon-dom/master/dist/bacon-dom.Bindings.js).

There's a [plain example-app](https://github.com/baconjs/bacon.jquery/tree/master/examples/plain) that uses script tags only.
There's a [plain example-app](https://github.com/baconjs/bacon-dom/tree/master/examples/plain) that uses script tags only.

## Use with Node / Browserify

BJQ is registered in the NPM repository as `bacon.jquery` and works fine with [node-browserify](https://github.com/substack/node-browserify).
BJQ is registered in the NPM repository as `bacon-dom` and works fine with [node-browserify](https://github.com/substack/node-browserify).

See the [browserify example-app](https://github.com/baconjs/bacon.jquery/tree/master/examples/browserify) for an example.
See the [browserify example-app](https://github.com/baconjs/bacon-dom/tree/master/examples/browserify) for an example.

## Use with Bower

Registered to the Bower registry as `bacon.jquery`. See the
Example Applications, for instance [requirejs example-app](https://github.com/baconjs/bacon.jquery/tree/master/examples/requirejs).
Registered to the Bower registry as `bacon-dom`. See the
Example Applications, for instance [requirejs example-app](https://github.com/baconjs/bacon-dom/tree/master/examples/requirejs).

## Building

The `bacon.jquery` module is built using NPM and Grunt.
The `bacon-dom` module is built using NPM and Grunt.

To build, use `npm install`.

@@ -269,11 +298,11 @@ The browser tests can also be run by opening the

The tests are also run automatically on [Travis CI](https://travis-ci.org/). See build status below.

[![Build Status](https://travis-ci.org/baconjs/bacon.jquery.png)](https://travis-ci.org/baconjs/bacon.jquery)
[![Build Status](https://travis-ci.org/baconjs/bacon-dom.png)](https://travis-ci.org/baconjs/bacon-dom)

## What next?

See [Issues](https://github.com/baconjs/bacon.jquery/issues).
See [Issues](https://github.com/baconjs/bacon-dom/issues).

If this seems like a good idea, please tell me so! If you'd like to
contribute, please do! Pull Requests, Issues etc appreciated. Star this project to let me know that you care.
9 changes: 6 additions & 3 deletions RELEASE-NOTES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
0.4.2 shrink code size (PR #28 by @tco)
0.4.1 don't use Array.prototype.indexOf
0.4.0 extracted bacon.model
## Release notes

- 0.5.0 Remove hard dependency on jQuery and rename to bacon-dom
- 0.4.2 shrink code size (PR #28 by @tco)
- 0.4.1 don't use Array.prototype.indexOf
- 0.4.0 extracted bacon.model
6 changes: 3 additions & 3 deletions bower.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "bacon.jquery",
"version": "0.4.11",
"main": "dist/bacon.jquery.js",
"name": "bacon-dom",
"version": "0.5.0",
"main": "dist/bacon-dom.js",
"ignore": ["browsertest", "examples", "src", "test", "./*.*", "build", "release", "run-tests", "version"]
}
72 changes: 36 additions & 36 deletions browsertest/BJB-tests.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
var expect = chai.expect

describe('bacon.jquery', function() {
describe('textFieldValue', function() {
describe('bacon-dom', function() {
describe('textField.value', function() {
var field
beforeEach(function() {
$('#bacon-dom').html('<input type="text" id="text" value="defaultVal">')
@@ -10,28 +10,28 @@ describe('bacon.jquery', function() {

describe('with initVal', function() {
it('sets value to DOM', function() {
var model = Bacon.$.textFieldValue(field, 'initVal')
var model = Bacon.$.textField.value(field, 'initVal')
expect(field.val()).to.equal('initVal')
})
it('sets the initVal as the initial value of the model', function() {
var model = Bacon.$.textFieldValue(field, 'initVal')
var model = Bacon.$.textField.value(field, 'initVal')
specifyValue(model, 'initVal')
})
})

describe('without initVal', function() {
it('leaves DOM unaffected', function() {
var model = Bacon.$.textFieldValue(field)
var model = Bacon.$.textField.value(field)
expect(field.val()).to.equal('defaultVal')
})
it('uses value from DOM as initial value of the model', function() {
var model = Bacon.$.textFieldValue(field)
var model = Bacon.$.textField.value(field)
specifyValue(model, 'defaultVal')
})
describe('with empty default value', function() {
it('waits for browser to autofill textfield', function(done) {
field.val('')
var model = Bacon.$.textFieldValue(field)
var model = Bacon.$.textField.value(field)
model.filter(function (v) {
return v
}).onValue(function() {
@@ -45,21 +45,21 @@ describe('bacon.jquery', function() {

describe('when setting value of model', function() {
it('sets value to DOM', function() {
Bacon.$.textFieldValue(field).set('newVal')
Bacon.$.textField.value(field).set('newVal')
expect(field.val()).to.equal('newVal')
})
})

describe('when DOM value changes', function() {
it('updates value of model', function() {
var model = Bacon.$.textFieldValue(field)
var model = Bacon.$.textField.value(field)
field.val("newVal")
field.trigger("keyup")
specifyValue(model, "newVal")
})

it('ignores duplicates', function() {
var model = Bacon.$.textFieldValue(field)
var model = Bacon.$.textField.value(field)
field.val("newVal")
field.trigger("keyup")
specifyValue(model, "newVal")
@@ -72,13 +72,13 @@ describe('bacon.jquery', function() {

describe('when element is not found', function() {
it('returns empty string as value', function() {
var model = Bacon.$.textFieldValue($('.asdfqwer'))
var model = Bacon.$.textField.value($('.asdfqwer'))
specifyValue(model, '')
})
})
})

describe('checkBoxValue', function() {
describe('checkBox.value', function() {
var field
beforeEach(function() {
$('#bacon-dom').html('<input type="checkbox" id="checkbox">')
@@ -87,52 +87,52 @@ describe('bacon.jquery', function() {

describe('with initVal', function() {
it('sets value to DOM', function() {
var model = Bacon.$.checkBoxValue(field, true)
var model = Bacon.$.checkBox.value(field, true)
expect(field.prop("checked")).to.equal(true)
})
it('sets the initVal as the initial value of the model', function() {
var model = Bacon.$.checkBoxValue(field, true)
var model = Bacon.$.checkBox.value(field, true)
specifyValue(model, true)
})
})

describe('without initVal', function() {
it('leaves DOM unaffected', function() {
var model = Bacon.$.checkBoxValue(field)
var model = Bacon.$.checkBox.value(field)
expect(field.prop("checked")).to.equal(false)
})
it('uses value from DOM as initial value of the model', function() {
var model = Bacon.$.checkBoxValue(field)
var model = Bacon.$.checkBox.value(field)
specifyValue(model, false)
})
})

describe('when setting value of model', function() {
it('sets value to DOM', function() {
Bacon.$.checkBoxValue(field).set(true)
Bacon.$.checkBox.value(field).set(true)
expect(field.prop("checked")).to.equal(true)
})
it('leaves defaultChecked property as is', function() {
Bacon.$.checkBoxValue(field).set(true)
Bacon.$.checkBox.value(field).set(true)
expect(field.prop("defaultChecked")).to.equal(false)
})
})
describe('when DOM value changes', function() {
it('updates value of model', function() {
var model = Bacon.$.checkBoxValue(field)
var model = Bacon.$.checkBox.value(field)
field.trigger("click")
specifyValue(model, true)
})
})
describe('when element is not found', function() {
it('returns false as value', function() {
var model = Bacon.$.checkBoxValue($('.asdfqwer'))
var model = Bacon.$.checkBox.value($('.asdfqwer'))
specifyValue(model, false)
})
})
})

describe('selectValue', function() {
describe('select.value', function() {
var field
beforeEach(function() {
$('#bacon-dom').html('<select id="select"><option value="a">A</option><option value="b" selected>B</option></select>')
@@ -141,64 +141,64 @@ describe('bacon.jquery', function() {

describe('with initVal', function() {
it('sets value to DOM', function() {
var model = Bacon.$.selectValue(field, 'a')
var model = Bacon.$.select.value(field, 'a')
expect(field.val()).to.equal('a')
})
it('sets the initVal as the initial value of the model', function() {
var model = Bacon.$.selectValue(field, 'a')
var model = Bacon.$.select.value(field, 'a')
specifyValue(model, 'a')
})
})

describe('without initVal', function() {
it('leaves DOM unaffected', function() {
var model = Bacon.$.selectValue(field)
var model = Bacon.$.select.value(field)
expect(field.val()).to.equal('b')
})
it('uses value from DOM as initial value of the model', function() {
var model = Bacon.$.selectValue(field)
var model = Bacon.$.select.value(field)
specifyValue(model, 'b')
})
})

describe('when setting value of model', function() {
it('sets value to DOM', function() {
Bacon.$.selectValue(field).set('a')
Bacon.$.select.value(field).set('a')
expect(field.val()).to.equal('a')
})
})
describe('when DOM value changes', function() {
it('updates value of model', function() {
var model = Bacon.$.selectValue(field)
var model = Bacon.$.select.value(field)
field.val("a")
field.trigger("change")
specifyValue(model, "a")
})
})
})

describe('selectValue without any options', function() {
describe('select.value without any options', function() {
it('sets `null` as initial value of the model', function() {
$('#bacon-dom').html('<select id="select"></select>')
var model = Bacon.$.selectValue($('#bacon-dom #select'))
var model = Bacon.$.select.value($('#bacon-dom #select'))
specifyValue(model, null)
})
})

describe('selectValue when element is not found', function() {
describe('select.value when element is not found', function() {
it('sets `undefined` as initial value of the model', function() {
var model = Bacon.$.selectValue($('.asdfqwer'))
var model = Bacon.$.select.value($('.asdfqwer'))
specifyValue(model, undefined)
})
})

describe('radioGroupValue', function() {
testRadioGroupValueModel(Bacon.$.radioGroupValue, "a", "b")
describe('radioGroup.value', function() {
testradioGroup.valueModel(Bacon.$.radioGroup.value, "a", "b")
})

describe('intRadioGroupValue', function() {
testRadioGroupValueModel(Bacon.$.intRadioGroupValue, 1, 2)
testRadioGroupValueModel(Bacon.$.intRadioGroupValue, 0, 23)
describe('radioGroup.intValue', function() {
testradioGroup.valueModel(Bacon.$.radioGroup.intValue, 1, 2)
testradioGroup.valueModel(Bacon.$.radioGroup.intValue, 0, 23)
})

testEventHelper('click')
4 changes: 2 additions & 2 deletions browsertest/runner.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<html>
<head>
<meta charset="utf-8">
<title>bacon.jquery Mocha Tests</title>
<title>bacon-dom Mocha Tests</title>
<link rel="stylesheet" href="lib/mocha/mocha.css" />
<script src="lib/jquery/jquery.min.js"></script>
<script src="lib/mockjax.js"></script>
@@ -10,7 +10,7 @@
<script src="lib/mocha/mocha.js"></script>
<script src="../node_modules/baconjs/dist/Bacon.js"></script>
<script src="../node_modules/bacon.model/dist/bacon.model.js"></script>
<script src="../dist/bacon.jquery.js"></script>
<script src="../dist/bacon-dom.js"></script>
<script>mocha.setup('bdd')</script>
<script src="BJB-tests.js"></script>
<script>
8 changes: 4 additions & 4 deletions component.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
{
"name": "bacon.jquery",
"version": "0.4.11",
"main": "dist/bacon.jquery.js",
"name": "bacon-dom",
"version": "0.5.0",
"main": "dist/bacon-dom.js",
"scripts": [
"dist/bacon.jquery.js"
"dist/bacon-dom.js"
],
"dependencies":{
"baconjs/bacon.js":"*"
306 changes: 306 additions & 0 deletions dist/bacon-dom.js
1 change: 1 addition & 0 deletions dist/bacon-dom.min.js
243 changes: 0 additions & 243 deletions dist/bacon.jquery.js

This file was deleted.

1 change: 0 additions & 1 deletion dist/bacon.jquery.min.js

This file was deleted.

2 changes: 1 addition & 1 deletion examples/plain/bower.json
Original file line number Diff line number Diff line change
@@ -11,6 +11,6 @@
"bacon": "~0.6",
"bacon.model": "~0.1",
"requirejs": "2.1.6",
"bacon.jquery": "~0"
"bacon-dom": "~0"
}
}
6 changes: 3 additions & 3 deletions examples/plain/index.html
Original file line number Diff line number Diff line change
@@ -3,13 +3,13 @@
<script src="bower_components/jquery/jquery.js"></script>
<script src="bower_components/bacon/dist/Bacon.js"></script>
<script src="bower_components/bacon.model/dist/bacon.model.js"></script>
<script src="bower_components/bacon.jquery/dist/bacon.jquery.js"></script>
<script src="bower_components/bacon-dom/dist/bacon-dom.js"></script>
<script type="text/javascript" language="javascript">
$(function() {
// binding for "left" text field
var left = Bacon.$.textFieldValue($("#left"))
var left = Bacon.$.textField.value($("#left"))
// binding for "right" text field
var right = Bacon.$.textFieldValue($("#right"))
var right = Bacon.$.textField.value($("#right"))
// make a two-way binding between these two
right.bind(left)
// Make a one-way side effect: update label text on changes, uppercase
2 changes: 1 addition & 1 deletion examples/requirejs/bower.json
Original file line number Diff line number Diff line change
@@ -11,6 +11,6 @@
"bacon": "~0.6",
"bacon.model": "~0.1",
"requirejs": "2.1.6",
"bacon.jquery": "~0"
"bacon-dom": "~0"
}
}
4 changes: 2 additions & 2 deletions examples/requirejs/example.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
require.config({
paths: {
"bacon.model": "bower_components/bacon.model/dist/bacon.model",
"bacon.jquery": "bower_components/bacon.jquery/dist/bacon.jquery",
"bacon-dom": "bower_components/bacon-dom/dist/bacon-dom",
"bacon": "bower_components/bacon/dist/Bacon",
"jquery": "bower_components/jquery/jquery"
}})
require(["bacon.jquery", "jquery"], function(bjq, $) {
require(["bacon-dom", "jquery"], function(bjq, $) {
// binding for "left" text field
var left = bjq.textFieldValue($("#left"))
// binding for "right" text field
26 changes: 16 additions & 10 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
{
"name": "bacon.jquery",
"version": "0.4.11",
"author": "Juha Paananen",
"name": "bacon-dom",
"version": "0.5.0",
"authors": [
"Juha Paananen",
"Kristian Mandrup"
],
"licenses": [
"MIT"
],
"dependencies": {
"baconjs": "~0.7.8"
"baconjs": ">=0.7.8"
},
"devDependencies": {
"coffee-script": "1.4.0",
"mocha": "~1.17",
"chai": "1.9.0",
"ender": "x",
"coffee-script": ">=1.4.0",
"mocha": ">=1.17",
"chai": ">=1.9.0",
"grunt": "0.4.1",
"grunt-cli": "0.1.13",
"grunt-contrib-coffee": "~0.10.0",
@@ -20,12 +24,14 @@
"grunt-contrib-uglify": "~0.2.2",
"phantomjs": "~1",
"mocha-phantomjs": "~3.3",
"jquery": "~2",
"bacon.model": "~0.1.6"
"bacon.model": ">=0.1.6"
},
"scripts": {
"test": "./run-tests",
"prepublish": "node_modules/grunt-cli/bin/grunt"
},
"main": "dist/bacon.jquery.js"
"main": [
"dist/bacon-dom.js",
"dist/bacon-dom.min.js"
]
}
22 changes: 22 additions & 0 deletions src/bacon-ajax.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
init ($) ->
# AJAX
$.ajax = (params, abort) ->
Bacon.fromPromise $.Request.ajax(params), abort

$.ajaxGet = (url, data, dataType, abort) ->
$.ajax({url, dataType, data}, abort)

$.ajaxGetJSON = (url, data, abort) ->
$.ajax({url, dataType: "json", data}, abort)

Bacon.$.ajaxPost = (url, data, dataType, abort) ->
$.ajax({url, dataType, data, type: "POST"}, abort)

$.ajaxGetScript = (url, abort) ->
$.ajax({url, dataType: "script"}, abort)

$.lazyAjax = (params) ->
Bacon.once(params).flatMap(Bacon.$.ajax)

Bacon.Observable::ajax = ->
@flatMapLatest $.ajax
45 changes: 45 additions & 0 deletions src/bacon-ajax.js
17 changes: 17 additions & 0 deletions src/bacon-dom-effects.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
module.exports = ($) ->

# Effects (jQuery compatible)
effectNames = [
"animate", "show", "hide", "toggle",
"fadeIn", "fadeOut", "fadeTo", "fadeToggle",
"slideDown", "slideUp", "slideToggle" ]

effects = {}

for e in effectNames
do (e) ->
effects[e + 'E'] = (args...) ->
Bacon.fromPromise @[e](args...).promise()

$.Extender.extend effects
$
26 changes: 26 additions & 0 deletions src/bacon-dom-effects.js
21 changes: 21 additions & 0 deletions src/bacon-dom-events.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
module.exports = ($) ->
# DOM Events (jQuery compatible)
eventNames = [
"keydown", "keyup", "keypress",
"click", "dblclick", "mousedown", "mouseup",
"mouseenter", "mouseleave", "mousemove", "mouseout", "mouseover",
"dragstart", "drag", "dragenter", "dragleave", "dragover", "drop", "dragend",
"resize", "scroll", "select", "change",
"submit",
"blur", "focus", "focusin", "focusout",
"load", "unload" ]
events = {}

for e in eventNames
do (e) ->
events[e + 'E'] = (args...) ->
@asEventStream e, args...

$.Extender.extend events
$.Extender.asEventStream = Bacon.$.asEventStream
$
27 changes: 27 additions & 0 deletions src/bacon-dom-events.js
105 changes: 105 additions & 0 deletions src/bacon-dom-input.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
module.exports = ($) ->
nonEmpty = (x) ->
x.length > 0

assertArrayOrJQC = (x) ->
unless typeof x is 'object' or x instanceof Array
throw new Error('Value must be either an object or an Array of objects which conform to a minimal element query interface')

asJQC = (x) ->
$.Selector.toJQC(x)

$.textField = {
interval: 50
take: 10
}

# Input element bindings
$.textField =
value: (element, options) ->
defaultOpt = $.textField

initValue = options.init
get = -> element.val() || ""
autofillPoller = ->
Bacon.interval(options.interval || defaultOpt.interval).take(options.take || defaultOpt.take).map(get).filter(nonEmpty).take 1
events = element.asEventStream("keyup input")
.merge(element.asEventStream("cut paste").delay(1))
.merge(autofillPoller())

Bacon.Binding {
initValue,
get,
events,
set: (value) -> element.val(value)
}

$.checkBox =
value: (element, options) ->
initValue = options.init
Bacon.Binding {
initValue,
get: -> element.prop("checked")||false,
events: element.asEventStream("change"),
set: (value) -> element.prop "checked", value
}

groupValue: (checkBoxes, options) ->
initValue = options.init
assertArrayOrJQC(checkBoxes)
checkBoxes = asJQC(checkBoxes)
Bacon.Binding {
initValue,
get: ->
checkBoxes.filter(":checked").map((i, elem) ->
$.Selector(elem).val()).toArray()
events: checkBoxes.asEventStream("change"),
set: (value) ->
checkBoxes.each (i, elem) ->
$.Selector(elem).prop "checked", $.indexOf(value, $.Selector(elem).val()) >= 0
}

$.select =
value: (element, options) ->
initValue = options.init
Bacon.Binding {
initValue,
get: -> element.val(),
events: element.asEventStream("change"),
set: (value) -> element.val value
}

$.radioGroup =
value: (radios, options) ->
initValue = options.init
assertArrayOrJQC(radios)
radios = asJQC(radios)
Bacon.Binding {
initValue,
get: -> radios.filter(":checked").first().val(),
events: radios.asEventStream("change"),
set: (value) ->
radios.each (i, elem) ->
$.Selector(elem).prop "checked", elem.value is value
}

intValue: (radios, options) ->
initValue = options.init
radioGroupValue = $.radioGroupValue(radios)
Bacon.Binding {
initValue,
get: ->
value = radioGroupValue.get()
if value?
parseInt(value)
else
value
events: radioGroupValue.syncEvents()
set: (value) ->
strValue = if value?
Number(value).toString()
else
value
radioGroupValue.set strValue
}

141 changes: 141 additions & 0 deletions src/bacon-dom-input.js
37 changes: 37 additions & 0 deletions src/bacon-dom.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
init = (Bacon, BaconModel, JQC) ->
JQC = JQC || {}

altIndxOf = (xs, x) ->
for y, i in xs
return i if x == y
-1

indxOf = (xs, x) ->
xs.indexOf x

Bacon.$.indexOf = if Array::indexOf then indxOf else altIndxOf

Bacon.$.Model = Bacon.Model

Bacon.$.Selector = JQC
Bacon.$.Request = JQC
Bacon.$.Promise = JQC
Bacon.$.Extender = JQC.fn

Bacon.$.plugin = (names...) ->
for name in names
plugin = require "./bacon-#{name}"
plugin Bacon.$

# return the full API
Bacon.$

if module?
Bacon = require "baconjs"
BaconModel = require "bacon.model"
module.exports = init Bacon, BaconModel, $
else
if typeof define == "function" and define.amd
define ["bacon", "bacon.model", $], init
else
init(@Bacon, @BaconModel, @$)
56 changes: 56 additions & 0 deletions src/bacon-dom.js
16 changes: 16 additions & 0 deletions src/bacon-promise.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
module.exports = ($) ->

# Deferred/Promise
Bacon.Observable::toDeferred = ->
value = undefined
dfd = $.Promise.deferred() || $.Deferred()
@take(1).endOnError().subscribe((evt) ->
if evt.hasValue()
value = evt.value()
dfd.notify(value)
else if evt.isError()
dfd.reject(evt.error)
else if evt.isEnd()
dfd.resolve(value)
)
dfd
24 changes: 24 additions & 0 deletions src/bacon-promise.js
168 changes: 0 additions & 168 deletions src/bacon.jquery.coffee

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
expect = require("chai").expect

bjq = require "../src/bacon.jquery"
bjq = require "../src/bacon-dom"

twice = (x) -> x * 2
Bacon = require "baconjs"
30 changes: 30 additions & 0 deletions test/bacon-dom.spec.js