From 25ca01248686f0cd69c9eba885cca8a93d8b883b Mon Sep 17 00:00:00 2001 From: Bradley Momberger Date: Thu, 8 Dec 2016 15:00:51 -0600 Subject: [PATCH 1/8] Add data shim so jQuery's data functions also respect domData. Fixes #42 --- can-jquery.js | 1 + can-jquery_test.js | 62 ++++++++++++++++++++++++++ data.js | 106 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 169 insertions(+) create mode 100644 data.js diff --git a/can-jquery.js b/can-jquery.js index 1edebc0..ef92726 100644 --- a/can-jquery.js +++ b/can-jquery.js @@ -11,6 +11,7 @@ var makeArray = require("can-util/js/make-array/make-array"); var mutate = require("can-util/dom/mutate/mutate"); var setImmediate = require("can-util/js/set-immediate/set-immediate"); var canViewModel = require("can-view-model"); +require("./data.js"); module.exports = ns.$ = $; diff --git a/can-jquery_test.js b/can-jquery_test.js index 93a0aaf..9e3dd75 100644 --- a/can-jquery_test.js +++ b/can-jquery_test.js @@ -403,3 +403,65 @@ QUnit.test("extra args to handler can be read using `%arguments`", function () { var p0 = ta.getElementsByTagName("p")[0]; canEvent.trigger.call(p0, "myevent", ["myarg1", "myarg2"]); }); + +QUnit.module("can-jquery/legacy - data functions", { + setup: function() { + enableLegacyMode($); + this.$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")); +}); + + diff --git a/data.js b/data.js new file mode 100644 index 0000000..55c9f88 --- /dev/null +++ b/data.js @@ -0,0 +1,106 @@ +/* global module, require */ +var $ = require("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; +}; From b6b799fbfde26d605e9c0f0de06e1aa96f59d556 Mon Sep 17 00:00:00 2001 From: Bradley Momberger Date: Tue, 2 May 2017 17:42:07 -0600 Subject: [PATCH 2/8] Document data.js, and import can-jquery from data --- can-jquery.js | 1 - data.js | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/can-jquery.js b/can-jquery.js index e0e2d7f..7307783 100644 --- a/can-jquery.js +++ b/can-jquery.js @@ -12,7 +12,6 @@ var setImmediate = require("can-util/js/set-immediate/set-immediate"); var canViewModel = require("can-view-model"); var MO = require("can-util/dom/mutation-observer/mutation-observer"); var CIDMap = require("can-util/js/cid-map/cid-map"); -require("./data.js"); module.exports = ns.$ = $; diff --git a/data.js b/data.js index 55c9f88..f647aea 100644 --- a/data.js +++ b/data.js @@ -1,5 +1,5 @@ /* global module, require */ -var $ = require("jquery"); +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"); From 07be9f97273a6f66c25e8253fc96599b4709fa0a Mon Sep 17 00:00:00 2001 From: Bradley Momberger Date: Tue, 2 May 2017 17:44:23 -0600 Subject: [PATCH 3/8] Add data.md --- docs/data.md | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 docs/data.md diff --git a/docs/data.md b/docs/data.md new file mode 100644 index 0000000..9ba9771 --- /dev/null +++ b/docs/data.md @@ -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 = $("
"); + +$el.data("foo", "bar"); +domData.get.call(el[0], "foo") // -> "bar" + +domData.set.call(el[0], { baz: "quux" }); +$el.data(); // -> { "foo": "bar", "baz": "quux" } +``` + From 62f3d60e3598846dd7286182ab2650c8b1062264 Mon Sep 17 00:00:00 2001 From: Bradley Momberger Date: Tue, 2 May 2017 18:04:57 -0600 Subject: [PATCH 4/8] Add reference to data.js in can-jquery_test --- can-jquery_test.js | 1 + 1 file changed, 1 insertion(+) diff --git a/can-jquery_test.js b/can-jquery_test.js index 29bc368..b8b4590 100644 --- a/can-jquery_test.js +++ b/can-jquery_test.js @@ -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() { From b0352c7b2e7167bcfd08068e9cdec67e14dfe8cd Mon Sep 17 00:00:00 2001 From: Bradley Momberger Date: Tue, 2 May 2017 18:47:29 -0600 Subject: [PATCH 5/8] Fix unrelated issue causing test breakage when dispatching KeyboardEvent from can-util tests --- can-jquery.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/can-jquery.js b/can-jquery.js index 7307783..f105a28 100644 --- a/can-jquery.js +++ b/can-jquery.js @@ -28,6 +28,12 @@ if ($) { // when using domEvents.dispatch/domEvents.trigger. var domDispatch = domEvents.dispatch; domEvents.dispatch = function(event, args) { + // check for dispatch of native event object, which + // is supported by domDispatch but not by jQuery + if(typeof event === "object" && !args) { + args = [event]; + event = event.type; + } if (!specialEvents[event] && !nativeDispatchEvents[event]) { $(this).trigger(event, args); } else { From d65b013428f871c178c72ca3ce96455693cadc98 Mon Sep 17 00:00:00 2001 From: Bradley Momberger Date: Tue, 2 May 2017 19:01:15 -0600 Subject: [PATCH 6/8] Working fix for native events with non-enumerable type properties --- can-jquery.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/can-jquery.js b/can-jquery.js index f105a28..d3259bd 100644 --- a/can-jquery.js +++ b/can-jquery.js @@ -30,9 +30,14 @@ var domDispatch = domEvents.dispatch; domEvents.dispatch = function(event, args) { // check for dispatch of native event object, which // is supported by domDispatch but not by jQuery - if(typeof event === "object" && !args) { - args = [event]; - event = event.type; + if(typeof event === "object" && !Object.getOwnPropertyDescriptor(event, "type")) { + // Some native events break jQuery dispatch by having non-enumerable + // type properties. + Object.defineProperty(event, "type", { + configurabe: true, + enumerable: true, + value: event.type + }); } if (!specialEvents[event] && !nativeDispatchEvents[event]) { $(this).trigger(event, args); From 81101259b7f3d9053e8697458573245f1709a2d8 Mon Sep 17 00:00:00 2001 From: Bradley Momberger Date: Tue, 2 May 2017 19:04:26 -0600 Subject: [PATCH 7/8] Remove incorrect comments from previous code --- can-jquery.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/can-jquery.js b/can-jquery.js index d3259bd..48663a7 100644 --- a/can-jquery.js +++ b/can-jquery.js @@ -28,8 +28,6 @@ if ($) { // when using domEvents.dispatch/domEvents.trigger. var domDispatch = domEvents.dispatch; domEvents.dispatch = function(event, args) { - // check for dispatch of native event object, which - // is supported by domDispatch but not by jQuery if(typeof event === "object" && !Object.getOwnPropertyDescriptor(event, "type")) { // Some native events break jQuery dispatch by having non-enumerable // type properties. From 9a2671c29f2ea9b4d7ce31bbe518b6586f5ed765 Mon Sep 17 00:00:00 2001 From: Bradley Momberger Date: Tue, 2 May 2017 19:05:17 -0600 Subject: [PATCH 8/8] Fix spelling of 'configurable' --- can-jquery.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/can-jquery.js b/can-jquery.js index 48663a7..8abff69 100644 --- a/can-jquery.js +++ b/can-jquery.js @@ -32,7 +32,7 @@ domEvents.dispatch = function(event, args) { // Some native events break jQuery dispatch by having non-enumerable // type properties. Object.defineProperty(event, "type", { - configurabe: true, + configurable: true, enumerable: true, value: event.type });