diff --git a/reskindex.js b/reskindex.js index 3ad1f36888..2b0d56aff1 100755 --- a/reskindex.js +++ b/reskindex.js @@ -22,6 +22,15 @@ try { process.exit(1); } +var skinfoFile = path.join('src', 'skins', skin, 'skinfo.json'); + +try { + fs.accessSync(skinfoFile, fs.F_OK); +} catch (e) { + console.log("Skin "+skin+" has no skinfo.json"); + process.exit(1); +} + try { fs.accessSync(path.join('src', 'skins', skin, 'views'), fs.F_OK); } catch (e) { @@ -46,7 +55,16 @@ strm.write(" * so you'd just be trying to swim upstream like a salmon.\n"); strm.write(" * You are not a salmon.\n"); strm.write(" */\n\n"); -strm.write("var sdk = require('matrix-react-sdk');\n\n"); +var mySkinfo = JSON.parse(fs.readFileSync(skinfoFile, "utf8")); + +strm.write("var skin = {\n"); +strm.write(" atoms: {},\n"); +strm.write(" molecules: {},\n"); +strm.write(" organisms: {},\n"); +strm.write(" templates: {},\n"); +strm.write(" pages: {}\n"); +strm.write("};\n"); +strm.write('\n'); var tree = { atoms: {}, @@ -71,15 +89,26 @@ for (var i = 0; i < files.length; ++i) { while (restOfPath.length) { currentPath += '.'+restOfPath[0]; if (subtree[restOfPath[0]] == undefined) { - strm.write('sdk.'+currentPath+' = {};\n'); + strm.write('skin.'+currentPath+' = {};\n'); strm.uncork(); } subtree[restOfPath[0]] = {}; restOfPath = restOfPath.slice(1); } - strm.write('sdk.'+module+" = require('./views/"+file+"');\n"); + strm.write('skin.'+module+" = require('./views/"+file+"');\n"); strm.uncork(); } + +strm.write("\n"); + +if (mySkinfo.baseSkin) { + strm.write("module.exports = require('"+mySkinfo.baseSkin+"');"); + strm.write("var extend = require('matrix-react-sdk/lib/extend');\n"); + strm.write("extend(module.exports, skin);\n"); +} else { + strm.write("module.exports = skin;"); +} + strm.end(); diff --git a/src/ComponentBroker.js b/src/ComponentBroker.js deleted file mode 100644 index 831312b1dc..0000000000 --- a/src/ComponentBroker.js +++ /dev/null @@ -1,46 +0,0 @@ -/* -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 ComponentBroker = function() { - this.components = {}; -}; - -ComponentBroker.prototype = { - get: function(name) { - if (this.components[name]) { - return this.components[name]; - } - return null; - }, - - set: function(name, module) { - this.components[name] = module; - } -}; - -// 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; - diff --git a/src/Skinner.js b/src/Skinner.js new file mode 100644 index 0000000000..a9be3795c9 --- /dev/null +++ b/src/Skinner.js @@ -0,0 +1,75 @@ +/* +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. +*/ + +function extractComponent(object, path) { + var subObject = object[path[0]] + if (subObject === undefined) { + return undefined; + } + if (path.length == 1) { + return subObject; + } else { + return extractComponent(subObject, path.slice(1)); + } +} + +class Skinner { + constructor() { + this.components = null; + } + + getComponent(name) { + if (this.components === null) { + throw new Error( + "Attempted to get a component before a skin has been loaded."+ + "This is probably because either:"+ + " a) Your app has not called sdk.loadSkin(), or"+ + " b) A component has called getComponent at the root level" + ); + } + var comp = extractComponent(this.components, name.split('.')); + if (comp) { + return comp; + } + throw new Error("No such component: "+name); + } + + load(skinObject) { + if (this.components !== null) { + throw new Error( + "Attempted to load a skin while a skin is already loaded"+ + "If you want to change the active skin, call resetSkin first" + ); + } + this.components = skinObject; + } + + reset() { + this.components = null; + } +} + +// We define one Skinner 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.mxSkinner === undefined) { + global.mxSkinner = new Skinner(); +} +module.exports = global.mxSkinner; + diff --git a/src/controllers/organisms/RoomList.js b/src/controllers/organisms/RoomList.js index 03e18547b6..12941d65d5 100644 --- a/src/controllers/organisms/RoomList.js +++ b/src/controllers/organisms/RoomList.js @@ -20,9 +20,7 @@ var React = require("react"); var MatrixClientPeg = require("../../MatrixClientPeg"); var RoomListSorter = require("../../RoomListSorter"); -var ComponentBroker = require('../../ComponentBroker'); - -var RoomTile = ComponentBroker.get("molecules/RoomTile"); +var sdk = require('../../index'); module.exports = { componentWillMount: function() { @@ -100,16 +98,17 @@ module.exports = { }, makeRoomTiles: function() { - var that = this; + var RoomTile = sdk.getComponent('molecules.RoomTile'); + var self = this; return this.state.roomList.map(function(room) { - var selected = room.roomId == that.props.selectedRoom; + var selected = room.roomId == self.props.selectedRoom; return ( ); }); diff --git a/src/controllers/organisms/RoomView.js b/src/controllers/organisms/RoomView.js index 10b375cdad..a40c1e633a 100644 --- a/src/controllers/organisms/RoomView.js +++ b/src/controllers/organisms/RoomView.js @@ -26,12 +26,7 @@ var dis = require("../../dispatcher"); var PAGINATE_SIZE = 20; var INITIAL_SIZE = 100; -var ComponentBroker = require('../../ComponentBroker'); - -var tileTypes = { - 'm.room.message': ComponentBroker.get('molecules/MessageTile'), - 'm.room.member': ComponentBroker.get('molecules/MRoomMemberTile') -}; +var sdk = require('../../index'); module.exports = { getInitialState: function() { @@ -220,6 +215,11 @@ module.exports = { }, getEventTiles: function() { + var tileTypes = { + 'm.room.message': sdk.getComponent('molecules.MessageTile'), + 'm.room.member': sdk.getComponent('molecules.MRoomMemberTile') + }; + var ret = []; var count = 0; diff --git a/src/controllers/pages/MatrixChat.js b/src/controllers/pages/MatrixChat.js index b4ae6dd5de..68da9f4e12 100644 --- a/src/controllers/pages/MatrixChat.js +++ b/src/controllers/pages/MatrixChat.js @@ -21,9 +21,7 @@ var RoomListSorter = require("../../RoomListSorter"); var dis = require("../../dispatcher"); -var ComponentBroker = require('../../ComponentBroker'); - -var Notifier = ComponentBroker.get('organisms/Notifier'); +var sdk = require('../../index'); module.exports = { getInitialState: function() { @@ -62,6 +60,7 @@ module.exports = { onAction: function(payload) { var roomIndexDelta = 1; + var Notifier = sdk.getComponent('organisms.Notifier'); switch (payload.action) { case 'logout': @@ -141,8 +140,10 @@ module.exports = { }, startMatrixClient: function() { + var Notifier = sdk.getComponent('organisms.Notifier'); + var cli = MatrixClientPeg.get(); - var that = this; + var self = this; cli.on('syncComplete', function() { var firstRoom = null; if (cli.getRooms() && cli.getRooms().length) { @@ -150,7 +151,7 @@ module.exports = { cli.getRooms() )[0].roomId; } - that.setState({ready: true, currentRoom: firstRoom}); + self.setState({ready: true, currentRoom: firstRoom}); dis.dispatch({action: 'focus_composer'}); }); Notifier.start(); diff --git a/src/controllers/templates/Login.js b/src/controllers/templates/Login.js index 51c2543b8d..80e5015278 100644 --- a/src/controllers/templates/Login.js +++ b/src/controllers/templates/Login.js @@ -22,8 +22,6 @@ var MatrixClientPeg = require("../../MatrixClientPeg"); var Matrix = require("matrix-js-sdk"); var dis = require("../../dispatcher"); -var ComponentBroker = require("../../ComponentBroker"); - module.exports = { getInitialState: function() { return { diff --git a/src/controllers/templates/Register.js b/src/controllers/templates/Register.js index 29063fb61e..3913216415 100644 --- a/src/controllers/templates/Register.js +++ b/src/controllers/templates/Register.js @@ -22,8 +22,6 @@ var MatrixClientPeg = require("../../MatrixClientPeg"); var Matrix = require("matrix-js-sdk"); var dis = require("../../dispatcher"); -var ComponentBroker = require("../../ComponentBroker"); - module.exports = { FieldErrors: { PasswordMismatch: 'PasswordMismatch', diff --git a/src/index.js b/src/index.js index adb0e04dc7..a631538622 100644 --- a/src/index.js +++ b/src/index.js @@ -14,10 +14,17 @@ See the License for the specific language governing permissions and limitations under the License. */ -'use strict'; +var Skinner = require('./Skinner'); + +module.exports.loadSkin = function(skinObject) { + Skinner.load(skinObject); +}; + +module.exports.resetSkin = function() { + Skinner.reset(); +}; + +module.exports.getComponent = function(componentName) { + return Skinner.getComponent(componentName); +}; -module.exports.atoms = {}; -module.exports.molecules = {}; -module.exports.organisms = {}; -module.exports.templates = {}; -module.exports.pages = {};