react_webpack_rails 0.0.5 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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