Skip to content
9 changes: 9 additions & 0 deletions can-jquery.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,15 @@ if ($) {
// when using domEvents.dispatch/domEvents.trigger.
var domDispatch = domEvents.dispatch;
domEvents.dispatch = function(event, args) {
if(typeof event === "object" && !Object.getOwnPropertyDescriptor(event, "type")) {
// Some native events break jQuery dispatch by having non-enumerable
// type properties.
Object.defineProperty(event, "type", {
configurable: true,
enumerable: true,
value: event.type
});
}
if (!specialEvents[event] && !nativeDispatchEvents[event]) {
$(this).trigger(event, args);
} else {
Expand Down
63 changes: 63 additions & 0 deletions can-jquery_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ var canEvent = require("can-event");
require("can-util/dom/events/inserted/inserted");
require("can-util/dom/events/removed/removed");
require("can-stache-bindings");
require("can-jquery/data");

QUnit.module("can-jquery/legacy - can-controls", {
setup: function() {
Expand Down Expand Up @@ -446,3 +447,65 @@ QUnit.test("should call correct `removed` handler when one is removed", function
fixture.append($el);
$el.remove();
});

QUnit.module("can-jquery/legacy - data functions", {
setup: function() {
enableLegacyMode($);
this.$div = $("<div />").appendTo("#qunit-fixture");
},
teardown: function() {
disableLegacyMode();
}
});

QUnit.test("data() compatibility with can-util/dom/data/", function() {
domData.set.call(this.$div[0], "foo", "bar");
QUnit.equal(this.$div.data("foo"), "bar");

this.$div.data("foo", "baz");
QUnit.equal(domData.get.call(this.$div[0], "foo"), "baz");
});

QUnit.test("data() returns full data object from domData.get() with no arguments", function() {
domData.set.call(this.$div[0], "foo", "bar");
QUnit.deepEqual(this.$div.data(), {"foo" : "bar"});

QUnit.deepEqual($.data(this.$div[0]), {"foo" : "bar"});
});

QUnit.test("data() destructures objects before passing to domData.set", function() {
this.$div.data({"foo": "baz"});
QUnit.equal(domData.get.call(this.$div[0], "foo"), "baz");
});

QUnit.test("hasData() checks both jQuery data and domData", function() {
domData.set.call(this.$div[0], "foo", "bar");
$.data(this.$div[0], "quux", "thud");
QUnit.ok($.hasData(this.$div[0], "foo"));
QUnit.ok($.hasData(this.$div[0], "quux"));
});

QUnit.test("removeData() also calls domData.clean", function() {
domData.set.call(this.$div[0], "foo", "bar");
domData.set.call(this.$div[0], "quux", "thud");

this.$div.removeData("foo");
QUnit.ok(!domData.get.call(this.$div[0], "foo"));
QUnit.equal(domData.get.call(this.$div[0], "quux"), "thud");

this.$div.removeData(); // remove all remaining data;
QUnit.ok(!domData.get.call(this.$div[0], "quux"));

// Repeat for static $.removeData
domData.set.call(this.$div[0], "foo", "bar");
domData.set.call(this.$div[0], "quux", "thud");

$.removeData(this.$div[0], "foo");
QUnit.ok(!domData.get.call(this.$div[0], "foo"));
QUnit.equal(domData.get.call(this.$div[0], "quux"), "thud");

$.removeData(this.$div[0]); // remove all remaining data;
QUnit.ok(!domData.get.call(this.$div[0], "quux"));
});


106 changes: 106 additions & 0 deletions data.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
/* global module, require */
var $ = require("can-jquery");
var domData = require("can-util/dom/data/data");
var each = require("can-util/js/each/each");
var assign = require("can-util/js/assign/assign");

module.exports = $;

var oldData = $.data;
var oldFnData = $.fn.data;
$.fn.data = function() {
var args = arguments,
ret = oldFnData.apply(this, arguments);

if(arguments.length < 1) {
// get all (from the first element in the jQ)
assign(ret, domData.get.call(this[0]));
return ret;
} else if(arguments.length === 1 && typeof arguments[0] === "string") {
// get named property
if(ret != null) {
return ret;
} else {
return this.get().reduce(function(val, el) {
return val != null ? val : domData.get.apply(el, args);
}, null);
}
} else {
// set
this.each(function(i, el) {
if(typeof args[0] === "string") {
domData.set.apply(el, args);
} else {
each(args[0], function(val, key) {
domData.set.call(el, key, val);
});
}
});
return ret;
}
};

$.data = function() {
var elem = arguments[0],
args = [].slice.call(arguments, 1),
ret = oldData.apply(this, arguments);

if(arguments.length < 2) {
// get all
assign(ret, domData.get.call(elem));
return ret;
} else if(arguments.length === 2 && typeof arguments[1] === "string") {
// get named property
return ret != null ? ret : domData.get.apply(elem, args);
} else {
if(typeof args[0] === "string") {
domData.set.apply(elem, args);
} else {
each(args[0], function(val, key) {
domData.set.call(elem, key, val);
});
}
return ret;
}
};

var oldHasData = $.hasData;
$.hasData = function() {
var elem = arguments[0],
args = [].slice.call(arguments, 1);
return oldHasData.apply(this, arguments) || domData.get.call(elem).hasOwnProperty(args[0]);
};

var oldRemoveData = $.removeData;
var oldFnRemoveData = $.fn.removeData;

$.fn.removeData = function() {
var args = arguments,
ret = oldFnRemoveData.apply(this, arguments);

this.each(function(i, el) {
if(typeof args[0] === "string") {
domData.clean.apply(el, args);
} else {
each(domData.get.call(el), function(val, key) {
domData.clean.call(el, key);
});
}
});
return ret;
};

$.removeData = function() {
var elem = arguments[0],
args = [].slice.call(arguments, 1),
ret = oldRemoveData.apply(this, arguments);

if(typeof args[0] === "string") {
domData.clean.apply(elem, args);
} else {
each(domData.get.call(elem), function(val, key) {
domData.clean.call(elem, key);
});
}
return ret;
};
31 changes: 31 additions & 0 deletions docs/data.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
@module {jQuery} can-jquery/data can-jquery/data
@parent can-jquery.modules

@description Integrates the data functions of CanJS and jQuery.


Importing can-jquery/data will return the [jQuery object](http://api.jquery.com/jquery/). It will also import all non-legacy [can-jquery] features for event binding and dispatch.

```js
var $ = require("can-jquery/data");
```

@body

Importing `can-jquery/data` will also bring in [can-jquery], but also has the side effect of enabling jQuery data functions synchronizing with the [can-util/dom/data/data CanJS data store] and vice versa.

This means that data set via the [can-util/dom/data/data.set `domData.set`] function will be available when calling [`jQuery.data()`](https://api.jquery.com/jquery.data/) or [`jQuery.fn.data()`](https://api.jquery.com/data/) as a getter; conversely, using `jQuery.data()` or `jQuery.fn.data()` as a setter and calling [can-util/dom/data/data.get `domData.get`] will again make the set data available on get.

```js
var $ = require("can-jquery/data");
var domData = require("");

var $el = $("<div></div>");

$el.data("foo", "bar");
domData.get.call(el[0], "foo") // -> "bar"

domData.set.call(el[0], { baz: "quux" });
$el.data(); // -> { "foo": "bar", "baz": "quux" }
```