diff --git a/README.md b/README.md
index 82325cae47..14ef7c29cd 100644
--- a/README.md
+++ b/README.md
@@ -30,3 +30,10 @@ Note that you may need to restart the CSS builder if you add a new file. Note
that `npm start` builds debug versions of the the javascript and CSS, which are
much larger than the production versions build by the `npm run build` commands.
+IMPORTANT: If you customise components in your application (and hence require
+react from your app) you must be sure to:
+
+1. Make your app depend on react directly
+2. If you `npm link` matrix-react-sdk, manually remove the 'react' directory
+ from matrix-react-sdk's `node_modules` folder, otherwise browserify will
+ pull in both copies of react which causes the app to break.
diff --git a/examples/custom/CustomMTextTile.js b/examples/custom/CustomMTextTile.js
new file mode 100644
index 0000000000..983bd0b8fb
--- /dev/null
+++ b/examples/custom/CustomMTextTile.js
@@ -0,0 +1,40 @@
+/*
+Copyright 2015 OpenMarket Ltd
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+'use strict';
+
+var React = require('react');
+
+var MTextTileController = require("matrix-react-sdk/src/controllers/molecules/MTextTile");
+
+module.exports = React.createClass({
+ displayName: 'MTextTile',
+ mixins: [MTextTileController],
+
+ render: function() {
+ var content = this.props.mxEvent.getContent();
+ return (
+
+ {content.body}
+
+ );
+ },
+
+ onClick: function(ev) {
+ global.alert(this.props.mxEvent.getContent().body);
+ }
+});
+
diff --git a/examples/custom/README.md b/examples/custom/README.md
new file mode 100644
index 0000000000..8125053ce0
--- /dev/null
+++ b/examples/custom/README.md
@@ -0,0 +1,4 @@
+matrix-react-example
+====================
+
+An example of how to use the Matrix React SDK to build a more customised app
diff --git a/examples/custom/index.html b/examples/custom/index.html
new file mode 100644
index 0000000000..98703e2715
--- /dev/null
+++ b/examples/custom/index.html
@@ -0,0 +1,12 @@
+
+
+
+
+ Matrix Flux
+
+
+
+
+
+
+
diff --git a/examples/custom/index.js b/examples/custom/index.js
new file mode 100644
index 0000000000..d52c1d460c
--- /dev/null
+++ b/examples/custom/index.js
@@ -0,0 +1,40 @@
+/*
+Copyright 2015 OpenMarket Ltd
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+'use strict';
+
+// Remember to make your project depend on react directly as soon as
+// you add a require('react') to any file in your project. Do not rely
+// on react being pulled in via matrix-react-sdk: browserify breaks
+// horribly in this situation and can end up pulling in multiple copies
+// of react.
+var React = require("react");
+
+// We pull in the component broker first, separately, as we need to replace
+// components before the SDK loads.
+var ComponenetBroker = require("matrix-react-sdk/src/ComponentBroker");
+
+var CustomMTextTile = require('./CustomMTextTile');
+
+ComponenetBroker.set('molecules/MTextTile', CustomMTextTile);
+
+var MatrixReactSdk = require("matrix-react-sdk");
+//var MatrixReactSdk = require("../../src/index");
+
+React.render(
+ ,
+ document.getElementById('matrixchat')
+);
diff --git a/examples/custom/package.json b/examples/custom/package.json
new file mode 100644
index 0000000000..6acec803fa
--- /dev/null
+++ b/examples/custom/package.json
@@ -0,0 +1,29 @@
+{
+ "name": "matrix-react-example",
+ "version": "0.0.1",
+ "description": "Example usage of matrix-react-sdk",
+ "author": "matrix.org",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/matrix-org/matrix-react-sdk"
+ },
+ "license": "Apache-2.0",
+ "devDependencies": {
+ "browserify": "^10.2.3",
+ "envify": "^3.4.0",
+ "http-server": "^0.8.0",
+ "matrix-react-sdk": "../../",
+ "npm-css": "^0.2.3",
+ "parallelshell": "^1.2.0",
+ "reactify": "^1.1.1",
+ "uglify-js": "^2.4.23",
+ "watchify": "^3.2.1"
+ },
+ "scripts": {
+ "build": "browserify -t [ envify --NODE_ENV production ] -g reactify index.js | uglifyjs -c -m -o bundle.js",
+ "start": "parallelshell 'watchify -v -d -g reactify index.js -o bundle.js' 'http-server'"
+ },
+ "dependencies": {
+ "react": "^0.13.3"
+ }
+}
diff --git a/src/ComponentBroker.js b/src/ComponentBroker.js
index 0726106104..61b2d85ee0 100644
--- a/src/ComponentBroker.js
+++ b/src/ComponentBroker.js
@@ -16,31 +16,48 @@ limitations under the License.
'use strict';
-var components = {};
-
function load(name) {
var module = require("../skins/base/views/"+name);
- components[name] = module;
return module;
};
-module.exports = {
- get: function(name) {
- if (components[name]) return components[name];
+var ComponentBroker = function() {
+ this.components = {};
+};
- components[name] = load(name);
- return components[name];
+ComponentBroker.prototype = {
+ get: function(name) {
+ if (this.components[name]) {
+ return this.components[name];
+ }
+
+ this.components[name] = load(name);
+ return this.components[name];
},
set: function(name, module) {
- components[name] = module;
+ this.components[name] = module;
}
};
-// Statically require all the components we know about,
-// otherwise browserify has no way of knowing what module to include
+// We define one Component Broker globally, because the intention is
+// very much that it is a singleton. Relying on there only being one
+// copy of the module can be dicey and not work as browserify's
+// behaviour with multiple copies of files etc. is erratic at best.
+// XXX: We can still end up with the same file twice in the resulting
+// JS bundle which is nonideal.
+if (global.componentBroker === undefined) {
+ global.componentBroker = new ComponentBroker();
+}
+module.exports = global.componentBroker;
+
+// We need to tell browserify to include all the components
+// by direct require syntax in here, but we don't want them
+// to be evaluated in this file because then we wouldn't be
+// able to override them. if (0) does this.
// Must be in this file (because the require is file-specific) and
// must be at the end because the components include this file.
+if (0) {
require('../skins/base/views/atoms/LogoutButton');
require('../skins/base/views/atoms/EnableNotificationsButton');
require('../skins/base/views/atoms/MessageTimestamp');
@@ -62,3 +79,4 @@ require('../skins/base/views/organisms/RoomList');
require('../skins/base/views/organisms/RoomView');
require('../skins/base/views/templates/Login');
require('../skins/base/views/organisms/Notifier');
+}