diff --git a/addon/modifiers/from-event.js b/addon/modifiers/from-event.js
new file mode 100644
index 0000000..ac4d3a5
--- /dev/null
+++ b/addon/modifiers/from-event.js
@@ -0,0 +1,71 @@
+import Ember from "ember";
+import { fromEvent } from "rxjs";
+
+export default Ember._setModifierManager(
+ () => ({
+ createModifier() {
+ return {
+ subscription: undefined,
+ element: undefined
+ };
+ },
+
+ _setupSubscription(state, eventName, operatorOrObserver, maybeObserver) {
+ const { element } = state;
+ let operator, observer;
+
+ if (operatorOrObserver && maybeObserver) {
+ operator = operatorOrObserver;
+ observer = maybeObserver;
+ } else if (operatorOrObserver && !maybeObserver) {
+ observer = operatorOrObserver;
+ }
+
+ let observable = fromEvent(element, eventName);
+
+ if (operator) {
+ observable = observable.pipe(operator);
+ }
+
+ state.subscription = observable.subscribe(observer);
+ },
+
+ installModifier(
+ state,
+ element,
+ {
+ positional: [eventName, operatorOrObserver, maybeObserver]
+ }
+ ) {
+ state.element = element;
+
+ this._setupSubscription(
+ state,
+ eventName,
+ operatorOrObserver,
+ maybeObserver
+ );
+ },
+
+ updateModifier(
+ state,
+ {
+ positional: [eventName, operatorOrSubscribe, maybeObserver]
+ }
+ ) {
+ state.subscription.unsubscribe();
+
+ this._setupSubscription(
+ state,
+ eventName,
+ operatorOrSubscribe,
+ maybeObserver
+ );
+ },
+
+ destroyModifier({ subscription }) {
+ subscription.unsubscribe();
+ }
+ }),
+ class FromEventModifier {}
+);
diff --git a/app/modifiers/from-event.js b/app/modifiers/from-event.js
new file mode 100644
index 0000000..739ef61
--- /dev/null
+++ b/app/modifiers/from-event.js
@@ -0,0 +1 @@
+export { default } from "ember-observable/modifiers/from-event";
diff --git a/config/ember-try.js b/config/ember-try.js
index e54ee4b..ba8b000 100644
--- a/config/ember-try.js
+++ b/config/ember-try.js
@@ -21,6 +21,7 @@ module.exports = function() {
npm: {
devDependencies: {
"@ember/jquery": "^0.5.1",
+ "ember-modifier-manager-polyfill": "^1.0.1",
"ember-source": "~2.18.0"
}
}
@@ -29,6 +30,7 @@ module.exports = function() {
name: "ember-lts-3.4",
npm: {
devDependencies: {
+ "ember-modifier-manager-polyfill": "^1.0.1",
"ember-source": "~3.4.0"
}
}
@@ -37,6 +39,7 @@ module.exports = function() {
name: "ember-release",
npm: {
devDependencies: {
+ "ember-modifier-manager-polyfill": "^1.0.1",
"ember-source": urls[0]
}
}
@@ -45,6 +48,7 @@ module.exports = function() {
name: "ember-beta",
npm: {
devDependencies: {
+ "ember-modifier-manager-polyfill": "^1.0.1",
"ember-source": urls[1]
}
}
@@ -53,6 +57,7 @@ module.exports = function() {
name: "ember-canary",
npm: {
devDependencies: {
+ "ember-modifier-manager-polyfill": "^1.0.1",
"ember-source": urls[2]
}
}
diff --git a/package.json b/package.json
index 06a67d7..5064677 100644
--- a/package.json
+++ b/package.json
@@ -44,6 +44,7 @@
"ember-export-application-global": "^2.0.0",
"ember-load-initializers": "^1.1.0",
"ember-maybe-import-regenerator": "^0.1.6",
+ "ember-modifier-manager-polyfill": "^1.0.1",
"ember-qunit": "^3.4.1",
"ember-resolver": "^5.0.1",
"ember-source": "~3.7.0",
diff --git a/tests/integration/modifiers/from-event-test.js b/tests/integration/modifiers/from-event-test.js
new file mode 100644
index 0000000..342431f
--- /dev/null
+++ b/tests/integration/modifiers/from-event-test.js
@@ -0,0 +1,99 @@
+import { module, test } from "qunit";
+import { setupRenderingTest } from "ember-qunit";
+import { setupScheduler } from "ember-observable/test-support";
+import { render, click } from "@ember/test-helpers";
+import { Subject } from "rxjs";
+import { filter } from "rxjs/operators";
+import hbs from "htmlbars-inline-precompile";
+import td from "testdouble";
+
+module("Integration | Modifier | from-event", function(hooks) {
+ setupRenderingTest(hooks);
+ setupScheduler(hooks);
+
+ test("it can subscribe to events", async function(assert) {
+ this.observer = td.function();
+
+ await render(hbs`
+
+ `);
+
+ await click("button");
+
+ assert.verify(
+ this.observer(td.matchers.isA(MouseEvent)),
+ "The observer was called with the event"
+ );
+ });
+
+ test("it can pipe the observable through an operator", async function(assert) {
+ this.operator = filter((_event, index) => index % 2 === 0);
+ this.observer = td.function();
+
+ await render(hbs`
+
+ `);
+
+ await click("button");
+ await click("button");
+
+ assert.verify(
+ this.observer(td.matchers.isA(MouseEvent)),
+ { times: 1 },
+ "The observer was called one time"
+ );
+ });
+
+ test("it handles the arguments changing", async function(assert) {
+ const originalObserver = td.function("original observer");
+ const newObserver = td.function("new observer");
+
+ this.observer = originalObserver;
+
+ await render(hbs`
+
+ `);
+
+ this.set("observer", newObserver);
+
+ await click("button");
+
+ assert.verify(
+ originalObserver(td.matchers.isA(MouseEvent)),
+ { times: 0 },
+ "The original observer is never called"
+ );
+
+ assert.verify(
+ newObserver(td.matchers.isA(MouseEvent)),
+ { times: 1 },
+ "The new observer is called"
+ );
+ });
+
+ test("it can receive a `Subject` to surface the observable", async function(assert) {
+ this.subject = new Subject();
+ const observer = td.function("Original observer");
+
+ this.subject.subscribe(observer);
+
+ await render(hbs`
+
+ `);
+
+ await click("button");
+
+ assert.verify(
+ observer(td.matchers.isA(MouseEvent)),
+ "The observer is called through the Subject"
+ );
+ });
+});
diff --git a/yarn.lock b/yarn.lock
index 8a88570..59b817a 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1347,7 +1347,7 @@ babel-plugin-debug-macros@^0.1.10:
dependencies:
semver "^5.3.0"
-babel-plugin-debug-macros@^0.2.0-beta.6:
+babel-plugin-debug-macros@^0.2.0, babel-plugin-debug-macros@^0.2.0-beta.6:
version "0.2.0"
resolved "https://registry.yarnpkg.com/babel-plugin-debug-macros/-/babel-plugin-debug-macros-0.2.0.tgz#0120ac20ce06ccc57bf493b667cf24b85c28da7a"
integrity sha512-Wpmw4TbhR3Eq2t3W51eBAQSdKlr+uAyF0GI4GtPfMCD12Y4cIdpKC9l0RjNTH/P9isFypSqqewMPm7//fnZlNA==
@@ -3668,6 +3668,30 @@ ember-cli-babel@^7.1.2, ember-cli-babel@^7.1.3, ember-cli-babel@^7.2.0, ember-cl
ensure-posix-path "^1.0.2"
semver "^5.5.0"
+ember-cli-babel@^7.4.0:
+ version "7.4.1"
+ resolved "https://registry.yarnpkg.com/ember-cli-babel/-/ember-cli-babel-7.4.1.tgz#9892f5883f5a6b1f0f86fb1331fc491338f372ad"
+ integrity sha512-h6qZKHyULm5SYhvjNOeXvLl3kHaBdh37g5QqTTiC/vMiWP/xnyNp2bMoq52qq+SLm/bE8+5UcVTKjrNl0+IqXA==
+ dependencies:
+ "@babel/core" "^7.0.0"
+ "@babel/plugin-transform-modules-amd" "^7.0.0"
+ "@babel/plugin-transform-runtime" "^7.2.0"
+ "@babel/polyfill" "^7.0.0"
+ "@babel/preset-env" "^7.0.0"
+ "@babel/runtime" "^7.2.0"
+ amd-name-resolver "^1.2.1"
+ babel-plugin-debug-macros "^0.2.0-beta.6"
+ babel-plugin-ember-modules-api-polyfill "^2.6.0"
+ babel-plugin-module-resolver "^3.1.1"
+ broccoli-babel-transpiler "^7.1.0"
+ broccoli-debug "^0.6.4"
+ broccoli-funnel "^2.0.1"
+ broccoli-source "^1.1.0"
+ clone "^2.1.2"
+ ember-cli-version-checker "^2.1.2"
+ ensure-posix-path "^1.0.2"
+ semver "^5.5.0"
+
ember-cli-broccoli-sane-watcher@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/ember-cli-broccoli-sane-watcher/-/ember-cli-broccoli-sane-watcher-3.0.0.tgz#dc1812c047e1ceec4413d3c41b51a9ffc61b4cfe"
@@ -3810,7 +3834,7 @@ ember-cli-uglify@^2.1.0:
broccoli-uglify-sourcemap "^2.1.1"
lodash.defaultsdeep "^4.6.0"
-ember-cli-version-checker@^2.0.0, ember-cli-version-checker@^2.1.0, ember-cli-version-checker@^2.1.2:
+ember-cli-version-checker@^2.0.0, ember-cli-version-checker@^2.1.0, ember-cli-version-checker@^2.1.1, ember-cli-version-checker@^2.1.2:
version "2.2.0"
resolved "https://registry.yarnpkg.com/ember-cli-version-checker/-/ember-cli-version-checker-2.2.0.tgz#47771b731fe0962705e27c8199a9e3825709f3b3"
integrity sha512-G+KtYIVlSOWGcNaTFHk76xR4GdzDLzAS4uxZUKdASuFX0KJE43C6DaqL+y3VTpUFLI2FIkAS6HZ4I1YBi+S3hg==
@@ -3922,6 +3946,15 @@ ember-cli@~3.7.1:
watch-detector "^0.1.0"
yam "^1.0.0"
+ember-compatibility-helpers@^1.2.0-beta.1:
+ version "1.2.0-beta.1"
+ resolved "https://registry.yarnpkg.com/ember-compatibility-helpers/-/ember-compatibility-helpers-1.2.0-beta.1.tgz#cd5898734f398f977707cbf8d448689377449180"
+ integrity sha512-ewKxBP0DIcbuMyGR8P+ned3H6vgCI5+2t+5MOwcaIFxRYUx6Bm0Dqk6Y8UWzwVgkxlZspC34k8QE/QLlSI7oiA==
+ dependencies:
+ babel-plugin-debug-macros "^0.2.0"
+ ember-cli-version-checker "^2.1.1"
+ semver "^5.4.1"
+
ember-disable-prototype-extensions@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/ember-disable-prototype-extensions/-/ember-disable-prototype-extensions-1.1.3.tgz#1969135217654b5e278f9fe2d9d4e49b5720329e"
@@ -3951,6 +3984,15 @@ ember-maybe-import-regenerator@^0.1.6:
ember-cli-babel "^6.0.0-beta.4"
regenerator-runtime "^0.9.5"
+ember-modifier-manager-polyfill@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/ember-modifier-manager-polyfill/-/ember-modifier-manager-polyfill-1.0.1.tgz#98e7dbda0a8e16137057ef23cd8e23bfb38d15cf"
+ integrity sha512-mOur7Kkh84FpCwvYnANQ5YD4jq2YcFW6zQUhJC5VW90etvtsSj7lVXWL5CZrxs0KskPCNAm0+b7LAtr0T6k9sA==
+ dependencies:
+ ember-cli-babel "^7.4.0"
+ ember-cli-version-checker "^2.1.2"
+ ember-compatibility-helpers "^1.2.0-beta.1"
+
ember-qunit@^3.4.1:
version "3.5.3"
resolved "https://registry.yarnpkg.com/ember-qunit/-/ember-qunit-3.5.3.tgz#bfd0bff8298c78c77e870cca43fe0826e78a0d09"