react_webpack_rails 0.0.5 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,121 @@
1
+ import expect, { spyOn, createSpy } from 'expect';
2
+ import Nodes from '../src/nodes';
3
+ import IntegrationsManager from '../src/integrations-manager';
4
+
5
+ const { mountNodes, unmountNodes } = Nodes;
6
+
7
+ const node = {
8
+ nodeType: 1,
9
+ nodeName: 'DIV',
10
+ getAttribute: createSpy().andCall(function (attribute) {
11
+ return {
12
+ 'data-react-element': 'data-react-component',
13
+ 'data-payload': '{"color":"sampleColor"}',
14
+ 'data-integration-name': 'basicIntegration',
15
+ 'data-options': '{"prerender":false}',
16
+ }[attribute];
17
+ }),
18
+ };
19
+
20
+ describe('Nodes', function () {
21
+ beforeEach(function () {
22
+ IntegrationsManager.register(
23
+ 'basicIntegration',
24
+ {
25
+ mount: () => {},
26
+ unmount: () => {},
27
+ }
28
+ );
29
+ });
30
+
31
+ afterEach(function () {
32
+ IntegrationsManager.integrations = {};
33
+ expect.restoreSpies();
34
+ });
35
+
36
+ describe('#mountNodes', function () {
37
+ context('when nodes could not be found', function () {
38
+ beforeEach(function () {
39
+ global.document = {
40
+ querySelectorAll: createSpy().andReturn([]),
41
+ };
42
+ });
43
+
44
+ it('does nothing', function () {
45
+ const mountSpy = spyOn(IntegrationsManager.get('basicIntegration'), 'mount');
46
+ mountNodes('[selectorWithoutNodes]');
47
+
48
+ expect(mountSpy.calls.length).toEqual(0);
49
+ });
50
+ });
51
+
52
+ context('when nodes were found', function () {
53
+ beforeEach(function () {
54
+ global.document = {
55
+ querySelectorAll: createSpy().andReturn([node]),
56
+ };
57
+ });
58
+
59
+ it('uses "data-react-element" as default selector', function () {
60
+ const documentSpy = spyOn(document, 'querySelectorAll');
61
+ mountNodes();
62
+
63
+ expect(documentSpy.calls.length).toEqual(1);
64
+ expect(documentSpy).toHaveBeenCalledWith('[data-react-element]');
65
+ });
66
+
67
+ it('mounts nodes', function () {
68
+ const mountSpy = spyOn(IntegrationsManager.get('basicIntegration'), 'mount');
69
+ const documentSpy = spyOn(document, 'querySelectorAll');
70
+ mountNodes('[selectorWithNodes]');
71
+
72
+ expect(mountSpy.calls.length).toEqual(1);
73
+ expect(documentSpy.calls.length).toEqual(1);
74
+ expect(documentSpy).toHaveBeenCalledWith('[selectorWithNodes]');
75
+ });
76
+ });
77
+ });
78
+
79
+ describe('#unmountNodes', function () {
80
+ context('when nodes could not be found', function () {
81
+ beforeEach(function () {
82
+ global.document = {
83
+ querySelectorAll: createSpy().andReturn([]),
84
+ };
85
+ });
86
+
87
+ it('does nothing', function () {
88
+ const unmountSpy = spyOn(IntegrationsManager.get('basicIntegration'), 'unmount');
89
+ unmountNodes('[selectorWithoutNodes]');
90
+
91
+ expect(unmountSpy.calls.length).toEqual(0);
92
+ });
93
+ });
94
+
95
+ context('when nodes were found', function () {
96
+ beforeEach(function () {
97
+ global.document = {
98
+ querySelectorAll: createSpy().andReturn([node]),
99
+ };
100
+ });
101
+
102
+ it('uses "data-react-element" as default selector', function () {
103
+ const documentSpy = spyOn(document, 'querySelectorAll');
104
+ unmountNodes();
105
+
106
+ expect(documentSpy.calls.length).toEqual(1);
107
+ expect(documentSpy).toHaveBeenCalledWith('[data-react-element]');
108
+ });
109
+
110
+ it('unmounts nodes', function () {
111
+ const unmountSpy = spyOn(IntegrationsManager.get('basicIntegration'), 'unmount');
112
+ const documentSpy = spyOn(document, 'querySelectorAll');
113
+ unmountNodes('[selectorsWithNodes]');
114
+
115
+ expect(unmountSpy.calls.length).toEqual(1);
116
+ expect(documentSpy.calls.length).toEqual(1);
117
+ expect(documentSpy).toHaveBeenCalledWith('[selectorsWithNodes]');
118
+ });
119
+ });
120
+ });
121
+ });
@@ -1,169 +1,88 @@
1
- /*globals React, Turbolinks*/
2
-
3
- // from https://github.com/reactjs/react-rails/blob/master/lib/assets/javascripts/react_ujs.js.erb
4
- // Unobtrusive scripting adapter for React
5
- ;(function(document, window) {
6
- // jQuery is optional. Use it to support legacy browsers.
7
- var $ = (typeof window.jQuery !== 'undefined') && window.jQuery;
8
-
9
- var _ReactDOM = function () {
10
- if(typeof window.ReactDOM !== 'undefined'){
11
- return window.ReactDOM;
12
- };
13
- if(parseFloat(window.React.version) >= 0.14) {
14
- console.warn("ReactDOM is missing. Make sure it's exposed in app/react/index.js");
15
- };
16
- return window.React;
17
- }
18
-
19
- // create the namespace
20
- window.ReactRailsUJS = {
21
- CLASS_NAME_ATTR: 'data-react-class',
22
- PROPS_ATTR: 'data-react-props',
23
- ROUTER_FLAG: 'data-react-router',
24
- RAILS_ENV_DEVELOPMENT: <%= Rails.env == "development" %>,
25
- reactComponents: {},
26
- reactRouters: {},
27
- // helper method for the mount and unmount methods to find the
28
- // `data-react-class` DOM elements
29
- _findDOMNodes: function(searchSelector) {
30
- // we will use fully qualified paths as we do not bind the callbacks
31
- var selector;
32
- if (typeof searchSelector === 'undefined') {
33
- var selector = '[' + window.ReactRailsUJS.CLASS_NAME_ATTR + ']';
34
- } else {
35
- var selector = searchSelector + ' [' + window.ReactRailsUJS.CLASS_NAME_ATTR + ']';
36
- }
37
-
38
- if ($) {
39
- return $(selector);
40
- } else {
41
- return document.querySelectorAll(selector);
42
- }
43
- },
44
-
45
- registerComponent: function (name, component) {
46
- window.ReactRailsUJS.reactComponents[name] = component;
47
- },
48
-
49
- getComponent: function(name) {
50
- return window.ReactRailsUJS.reactComponents[name];
51
- },
52
-
53
- createComponent: function (name, props) {
54
- var constructor = window.ReactRailsUJS.getComponent(name);
55
- return React.createElement(constructor, props);
56
- },
57
-
58
- renderComponent: function (name, props, element) {
59
- var component = window.ReactRailsUJS.createComponent(name, props);
60
- _ReactDOM().render(component, element);
61
- },
62
-
63
- unmountComponent: function (node) {
64
- _ReactDOM().unmountComponentAtNode(node);
65
- },
66
-
67
- registerRouter: function(name, routes) {
68
- window.ReactRailsUJS.reactRouters[name] = routes;
69
- },
70
-
71
- getRouter: function(name) {
72
- return window.ReactRailsUJS.reactRouters[name];
73
- },
74
-
75
- renderRouter: function(name, element) {
76
- if(window.ReactRailsUJS.routerEnabled == true){
77
- throw new Error("Error when renering " + name + "router: can't render more than one router.")
78
- }
79
- window.ReactRailsUJS.routerEnabled = true;
80
- var router = window.ReactRailsUJS.getRouter(name);
81
- _ReactDOM().render(router, element);
82
- },
83
-
84
- mountComponents: function(searchSelector) {
85
- var nodes = window.ReactRailsUJS._findDOMNodes(searchSelector);
86
-
87
- for (var i = 0; i < nodes.length; ++i) {
88
- var node = nodes[i];
89
- var className = node.getAttribute(window.ReactRailsUJS.CLASS_NAME_ATTR);
90
- var propsJson = node.getAttribute(window.ReactRailsUJS.PROPS_ATTR);
91
- try {
92
- var isRouter = JSON.parse(node.getAttribute(window.ReactRailsUJS.ROUTER_FLAG));
93
- } catch(error) {
94
- var isRouter = false
95
- }
96
- var props = propsJson && JSON.parse(propsJson);
97
- if (isRouter) {
98
- window.ReactRailsUJS.renderRouter(className, node)
99
- } else {
100
- window.ReactRailsUJS.renderComponent(className, props, node)
101
- }
102
- }
103
- },
104
-
105
- unmountComponents: function(searchSelector) {
106
- var nodes = window.ReactRailsUJS._findDOMNodes(searchSelector);
107
- window.ReactRailsUJS.routerEnabled = false;
108
- for (var i = 0; i < nodes.length; ++i) {
109
- var node = nodes[i];
110
- window.ReactRailsUJS.unmountComponent(node);
111
- }
112
- }
113
- };
114
-
115
- // expose helpers globally
116
- window.registerComponent = ReactRailsUJS.registerComponent;
117
- window.getComponent = ReactRailsUJS.getComponent;
118
- window.createComponent = ReactRailsUJS.createComponent;
119
- window.renderComponent = ReactRailsUJS.renderComponent;
120
- window.unmountComponent = ReactRailsUJS.unmountComponent;
121
-
122
- window.registerRouter = ReactRailsUJS.registerRouter;
123
- window.getRouter = ReactRailsUJS.getRouter;
124
- window.renderRouter = ReactRailsUJS.renderRouter;
125
-
126
- // functions not exposed publicly
127
- function handleTurbolinksEvents () {
128
- var handleEvent;
1
+ var __RWR_ENV__ = {
2
+ name: "<%=Rails.env%>",
3
+ config: <%=JSON(Rails.application.config.react.shared)%>
4
+ };
5
+
6
+ function deprecatedError(helperName) {
7
+ var lines = [
8
+ helperName + ' was removed.',
9
+ 'use RWR.' + helperName + ' instead.',
10
+ 'check react_webpack_rails changelog for details.'
11
+ ]
12
+ console.error(lines.join("\n"));
13
+ }
14
+
15
+ function registerComponent() {
16
+ deprecatedError('registerComponent');
17
+ }
18
+
19
+ function getComponent() {
20
+ deprecatedError('getComponent');
21
+ }
22
+
23
+ function createComponent() {
24
+ deprecatedError('createComponent');
25
+ }
26
+
27
+ function renderComponent() {
28
+ deprecatedError('renderComponent');
29
+ }
30
+
31
+ function unmountComponent() {
32
+ deprecatedError('unmountComponent');
33
+ }
34
+
35
+ function renderRouter() {
36
+ deprecatedError('renderRouter');
37
+ }
38
+
39
+ function registerRouter() {
40
+ deprecatedError('registerRouter');
41
+ }
42
+
43
+ function unmountRouter() {
44
+ deprecatedError('unmountRouter');
45
+ }
46
+
47
+ function getRouter() {
48
+ deprecatedError('getRouter');
49
+ }
50
+
51
+ var RWRhandlers = {
52
+ _mountNodes: function _mountNodes() {
53
+ RWR.mountNodes();
54
+ },
55
+
56
+ _unmountNodes: function _unmountNodes() {
57
+ RWR.unmountNodes();
58
+ },
59
+
60
+ _handleEvent: function(eventName, callback) {
61
+ document.addEventListener(eventName, callback);
62
+ },
63
+
64
+ handleTurbolinksEvents: function handleTurbolinksEvents() {
129
65
  var unmountEvent;
130
66
 
131
- if ($) {
132
- handleEvent = function(eventName, callback) {
133
- $(document).on(eventName, callback);
134
- };
135
-
136
- } else {
137
- handleEvent = function(eventName, callback) {
138
- document.addEventListener(eventName, callback);
139
- };
140
- }
141
-
142
67
  if (Turbolinks.EVENTS) {
143
68
  unmountEvent = Turbolinks.EVENTS.BEFORE_UNLOAD;
144
69
  } else {
145
70
  unmountEvent = 'page:receive';
146
71
  Turbolinks.pagesCached(0);
147
-
148
- if (window.ReactRailsUJS.RAILS_ENV_DEVELOPMENT) {
149
- console.warn('The Turbolinks cache has been disabled (Turbolinks >= 2.4.0 is recommended). See https://github.com/reactjs/react-rails/issues/87 for more information.');
150
- }
151
72
  }
152
- handleEvent('page:change', function() {window.ReactRailsUJS.mountComponents()});
153
- handleEvent(unmountEvent, function() {window.ReactRailsUJS.unmountComponents()});
154
- }
73
+ RWRhandlers._handleEvent('page:change', RWRhandlers._mountNodes);
74
+ RWRhandlers._handleEvent(unmountEvent, RWRhandlers._unmountNodes);
75
+ },
155
76
 
156
- function handleNativeEvents() {
157
- if ($) {
158
- $(function() {window.ReactRailsUJS.mountComponents()});
159
- } else {
160
- document.addEventListener('DOMContentLoaded', function() {window.ReactRailsUJS.mountComponents()});
161
- }
162
- }
77
+ handleNativeEvents: function handleNativeEvents() {
78
+ document.addEventListener('DOMContentLoaded', RWRhandlers._mountNodes);
79
+ },
80
+ };
163
81
 
82
+ (function reactMain() {
164
83
  if (typeof Turbolinks !== 'undefined' && Turbolinks.supported) {
165
- handleTurbolinksEvents();
84
+ RWRhandlers.handleTurbolinksEvents();
166
85
  } else {
167
- handleNativeEvents();
86
+ RWRhandlers.handleNativeEvents();
168
87
  }
169
88
  })(document, window);
@@ -1,3 +1,3 @@
1
1
  {
2
- "stage": 1
2
+ "presets": ["stage-1", "es2015", "react"]
3
3
  }
@@ -16,7 +16,7 @@ module.exports = function (config) {
16
16
  {
17
17
  test: /\.jsx?$/,
18
18
  exclude: /node_modules/,
19
- loader: 'babel-loader'
19
+ loader: 'babel'
20
20
  }]
21
21
  },
22
22
  watch: true,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "<%="#{Rails.application.class.parent_name}"%>",
3
3
  "devDependencies": {
4
- "babel-eslint": "^4.1.3",
4
+ "babel-eslint": "^5.0.0-beta6",
5
5
  "eslint": "^1.7.3",
6
6
  "eslint-plugin-react": "^3.6.3",
7
7
  "expect": "^1.12.2",
@@ -11,19 +11,25 @@
11
11
  "karma-sinon": "^1.0.4",
12
12
  "karma-sourcemap-loader": "^0.3.6",
13
13
  "karma-webpack": "^1.7.0",
14
+ "mocha": "^2.3.4",
15
+ "sinon": "^1.17.2",
14
16
  "react-hot-loader": "^1.3.0",
15
17
  "webpack-dev-server": "^1.12.1",
16
18
  "webpack-notifier": "^1.2.1"
17
19
  },
18
20
  "dependencies": {
19
- "babel-core": "^5.8.25",
20
- "babel-loader": "^5.3.2",
21
+ "babel-core": "^6.4.0",
22
+ "babel-loader": "^6.2.1",
23
+ "babel-preset-es2015": "^6.3.13",
24
+ "babel-preset-react": "^6.3.13",
25
+ "babel-preset-stage-1": "^6.3.13",
21
26
  "extract-text-webpack-plugin": "^0.8.2",
22
27
  "node-sass": "^3.3.3",
23
28
  "react": "^0.14.0",
24
29
  "react-dom": "^0.14.0",
25
30
  <%= options.router ? ' "react-router": "1.0.0-rc3",' : ''%>
26
31
  "react-tools": "*",
32
+ "react-webpack-rails": "0.1.0",
27
33
  "sass-loader": "^3.0.0",
28
34
  "webpack": "^1.12.1"
29
35
  },
@@ -1,12 +1,10 @@
1
- import React from 'react';
2
- import ReactDOM from 'react-dom';
3
- window.React = React;
4
- window.ReactDOM = ReactDOM;
1
+ import RWR from 'react-webpack-rails';
2
+ window.RWR = RWR;
5
3
  <% if options.example %>
6
4
  import HelloWorld from './components/hello-world';
7
- registerComponent('HelloWorld', HelloWorld);
5
+ RWR.registerComponent('HelloWorld', HelloWorld);
8
6
  <% else %>
9
7
  // example usage:
10
8
  // import HelloWorld from './components/hello-world';
11
- // registerComponent('HelloWorld', HelloWorld);
9
+ // RWR.registerComponent('HelloWorld', HelloWorld);
12
10
  <% end %>
@@ -14,7 +14,7 @@ module.exports = {
14
14
  key: 'jsx',
15
15
  test: /\.jsx?$/,
16
16
  exclude: /(node_modules)/,
17
- loaders: ['babel-loader']
17
+ loader: 'babel'
18
18
  },
19
19
  {
20
20
  key: 'scss',
@@ -2,6 +2,11 @@ require 'react_webpack_rails/view_helpers'
2
2
 
3
3
  module ReactWebpackRails
4
4
  class Railtie < ::Rails::Railtie
5
+ config.react = ActiveSupport::OrderedOptions.new
6
+ # Sensible defaults. Can be overridden in application.rb
7
+ config.react.camelize_props = false # pass in an underscored hash but get a camelized hash
8
+ config.react.shared = {}
9
+
5
10
  initializer 'react_webpack_rails.view_helpers' do
6
11
  ActionView::Base.send :include, ViewHelpers
7
12
  end