├── .npmignore
├── .jshintrc
├── .babelrc
├── lib
├── .babelrc
├── Random.js
├── utils.js
├── queue.js
├── socket.js
└── ddp.js
├── src
├── .babelrc
├── Call.js
├── components
│ ├── createContainer.js
│ └── Mixin.js
├── CollectionFS
│ ├── FSCollectionImagesPreloader.js
│ ├── FSCollection.js
│ └── setProperties.js
├── user
│ ├── Accounts.js
│ └── User.js
├── Data.js
├── Collection.js
└── Meteor.js
├── dist
├── lib
│ ├── Random.js
│ ├── utils.js
│ ├── queue.js
│ ├── socket.js
│ └── ddp.js
├── Call.js
├── src
│ ├── Call.js
│ ├── components
│ │ ├── createContainer.js
│ │ └── Mixin.js
│ ├── Data.js
│ ├── CollectionFS
│ │ ├── FSCollection.js
│ │ ├── setProperties.js
│ │ └── FSCollectionImagesPreloader.js
│ ├── user
│ │ ├── Accounts.js
│ │ └── User.js
│ ├── Collection.js
│ └── Meteor.js
├── components
│ ├── createContainer.js
│ ├── ComplexListView.js
│ ├── ListView.js
│ └── Mixin.js
├── Data.js
├── CollectionFS
│ ├── FSCollection.js
│ ├── setProperties.js
│ └── FSCollectionImagesPreloader.js
├── user
│ ├── Accounts.js
│ └── User.js
├── Collection.js
└── Meteor.js
├── .gitignore
├── docs
├── Install.md
└── FSCollection.md
├── LICENSE
├── package.json
└── README.md
/.npmignore:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "esnext": true
3 | }
4 |
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [ "es2015", "stage-0", "react" ],
3 | "plugins": [
4 | ["transform-runtime", {
5 | "polyfill": false,
6 | "regenerator": true
7 | }]
8 | ]
9 | }
10 |
--------------------------------------------------------------------------------
/lib/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [ "es2015", "stage-0", "react" ],
3 | "plugins": [
4 | ["transform-runtime", {
5 | "polyfill": false,
6 | "regenerator": true
7 | }]
8 | ]
9 | }
10 |
--------------------------------------------------------------------------------
/src/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [ "es2015", "stage-0", "react" ],
3 | "plugins": [
4 | ["transform-runtime", {
5 | "polyfill": false,
6 | "regenerator": true
7 | }]
8 | ]
9 | }
10 |
--------------------------------------------------------------------------------
/lib/Random.js:
--------------------------------------------------------------------------------
1 | const UNMISTAKABLE_CHARS = "23456789ABCDEFGHJKLMNPQRSTWXYZabcdefghijkmnopqrstuvwxyz";
2 |
3 | module.exports = {
4 | id(count = 17) {
5 | let res = "";
6 | for(let i=0;i;
29 | },
30 | });
31 | }
32 |
--------------------------------------------------------------------------------
/docs/Install.md:
--------------------------------------------------------------------------------
1 | # Android
2 |
3 | Add this to your AndroidManifest.xml file to autoreconnect fastly to DDP server if your device reconnects to network
4 |
5 | ```xml
6 |
7 | ```
8 |
9 |
10 |
11 | # Installing decorators
12 |
13 | ## With RN >= 0.16.0 (Babel 6)
14 |
15 | - `npm i --save-dev babel-plugin-transform-decorators-legacy babel-preset-react-native` in your project
16 | - Create a .babelrc file at the root of your project :
17 |
18 | ```json
19 | {
20 | "presets": ["react-native"],
21 | "plugins": ["transform-decorators-legacy"]
22 | }
23 | ```
24 |
25 | ## With RN <0.16.0 (Babel 5)
26 |
27 | Use a .babelrc file at the root of your project that contains :
28 |
29 | ```json
30 | {
31 | "optional": ["es7.decorators"],
32 | }
33 | ```
34 |
--------------------------------------------------------------------------------
/lib/queue.js:
--------------------------------------------------------------------------------
1 | export default class Queue {
2 |
3 | /*
4 | * As the name implies, `consumer` is the (sole) consumer of the queue.
5 | * It gets called with each element of the queue and its return value
6 | * serves as a ack, determining whether the element is removed or not from
7 | * the queue, allowing then subsequent elements to be processed.
8 | */
9 |
10 | constructor (consumer) {
11 | this.consumer = consumer;
12 | this.queue = [];
13 | }
14 |
15 | push (element) {
16 | this.queue.push(element);
17 | this.process();
18 | }
19 |
20 | process () {
21 | if (this.queue.length !== 0) {
22 | const ack = this.consumer(this.queue[0]);
23 | if (ack) {
24 | this.queue.shift();
25 | this.process();
26 | }
27 | }
28 | }
29 |
30 | empty () {
31 | this.queue = [];
32 | }
33 |
34 | }
--------------------------------------------------------------------------------
/docs/FSCollection.md:
--------------------------------------------------------------------------------
1 | # Implementation for Meteor-CollectionFS
2 |
3 | ## Example usage
4 |
5 | ```javascript
6 | @connectMeteor
7 | export default class ImageFS extends Component {
8 | startMeteorSubscriptions() {
9 | Meteor.subscribe('imagesFiles');
10 | }
11 | getMeteorData() {
12 | return {
13 | image: Meteor.FSCollection('imagesFiles').findOne()
14 | }
15 | }
16 | render() {
17 | const { image } = this.data;
18 |
19 | if(!image) return null;
20 |
21 | return (
22 |
26 | );
27 | }
28 | }
29 | ```
30 |
31 | ## Available methods on FSFile
32 |
33 | All methods accept an optional parameter to choose another store. Example `file.url({store: 'thumbnail'})`
34 |
35 | * url([store])
36 | * isImage([store])
37 | * isVideo([store])
38 | * isAudio([store])
39 | * isUploaded([store])
40 | * name([store])
41 | * extension([store])
42 | * size([store])
43 | * type([store])
44 | * updatedAt([store])
45 |
46 | ## Something wrong or missing ?
47 |
48 | Please create an issue or make a PR ;)
49 |
50 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 inProgress
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/src/CollectionFS/FSCollectionImagesPreloader.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import React, {
4 | Component,
5 | PropTypes
6 | } from 'react';
7 |
8 | import Data from '../Data';
9 | import setProperties from './setProperties';
10 |
11 | export default class FSCollectionImagesPreloader extends Component {
12 | static propTypes = {
13 | collection: PropTypes.string.isRequired,
14 | selector: PropTypes.oneOfType([ PropTypes.string, PropTypes.object ])
15 | };
16 | static defaultProps = {
17 | selector: {}
18 | };
19 | constructor(props) {
20 | super(props);
21 | this.state = {
22 | items: []
23 | };
24 | }
25 | componentWillMount() {
26 | const { collection, selector } = this.props;
27 |
28 |
29 | this.update = results=>{
30 | this.setState({
31 | items: results.map(elem=>setProperties(collection, elem))
32 | });
33 | };
34 |
35 | const collectionName = 'cfs.'+collection+'.filerecord';
36 |
37 | if(!Data.db[collectionName]) {
38 | Data.db.addCollection(collectionName)
39 | }
40 |
41 | this.items = Data.db.observe(() => {
42 | return Data.db[collectionName].find(selector);
43 | });
44 |
45 | this.items.subscribe(this.update);
46 | }
47 | componentWillUnmount() {
48 | this.items.dispose();
49 | }
50 | render() {
51 | const { items } = this.state;
52 |
53 | return (
54 |
55 | );
56 | }
57 | }
--------------------------------------------------------------------------------
/dist/src/components/createContainer.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 | exports.default = undefined;
7 |
8 | var _extends2 = require('babel-runtime/helpers/extends');
9 |
10 | var _extends3 = _interopRequireDefault(_extends2);
11 |
12 | var _react = require('react');
13 |
14 | var _react2 = _interopRequireDefault(_react);
15 |
16 | var _Mixin = require('./Mixin');
17 |
18 | var _Mixin2 = _interopRequireDefault(_Mixin);
19 |
20 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
21 |
22 | /**
23 | * Container helper using react-meteor-data.
24 | */
25 |
26 | function createContainer() {
27 | var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
28 | var Component = arguments[1];
29 |
30 | var expandedOptions = options;
31 | if (typeof options === 'function') {
32 | expandedOptions = {
33 | getMeteorData: options
34 | };
35 | }
36 |
37 | var _expandedOptions = expandedOptions;
38 | var _getMeteorData = _expandedOptions.getMeteorData;
39 |
40 |
41 | return _react2.default.createClass({
42 | displayName: 'MeteorDataContainer',
43 | mixins: [_Mixin2.default],
44 | getMeteorData: function getMeteorData() {
45 | return _getMeteorData(this.props);
46 | },
47 | render: function render() {
48 | return _react2.default.createElement(Component, (0, _extends3.default)({}, this.props, this.data));
49 | }
50 | });
51 | }
52 | exports.default = createContainer;
--------------------------------------------------------------------------------
/src/CollectionFS/FSCollection.js:
--------------------------------------------------------------------------------
1 | import EJSON from "ejson";
2 |
3 | import Collection from '../Collection';
4 | import Data from '../Data';
5 | import setProperties from './setProperties';
6 |
7 |
8 | if(!EJSON._getTypes()['FS.File']) {
9 | EJSON.addType('FS.File', function(value) {
10 | return {
11 | getFileRecord() {
12 | const collection = Data.db['cfs.'+value.collectionName+'.filerecord'];
13 |
14 | const item = collection && collection.get(value._id);
15 |
16 | if(!item) return value;
17 |
18 | return setProperties(value.collectionName, item);
19 | }
20 | };
21 | });
22 | }
23 |
24 | export default function(name) {
25 | const Meteor = this;
26 | const collectionName = 'cfs.'+name+'.filerecord';
27 |
28 |
29 | return {
30 | find(selector, options) {
31 | const elems = Collection(collectionName).find(selector, options);
32 | return elems.map(elem=>{
33 | return setProperties(name, elem);
34 | });
35 | },
36 | findOne(selector, options) {
37 | const elem = Collection(collectionName).findOne(selector, options);
38 | return elem && setProperties(name, elem);
39 | },
40 | insert: function() { Collection.apply(Meteor, [collectionName]).insert.apply(Meteor, arguments); },
41 | update: function() { Collection.apply(Meteor, [collectionName]).update.apply(Meteor, arguments); },
42 | remove: function() { Collection.apply(Meteor, [collectionName]).remove.apply(Meteor, arguments); },
43 | };
44 | }
45 |
46 |
47 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/src/user/Accounts.js:
--------------------------------------------------------------------------------
1 | import Data from '../Data';
2 | import call from '../Call';
3 | import User from './User';
4 | import { hashPassword } from '../../lib/utils';
5 |
6 |
7 | module.exports = {
8 | createUser(options, callback = ()=>{}) {
9 | if (options.username) options.username = options.username;
10 | if (options.email) options.email = options.email;
11 |
12 | // Replace password with the hashed password.
13 | options.password = hashPassword(options.password);
14 |
15 | User._startLoggingIn();
16 | call("createUser", options, (err, result)=>{
17 | User._endLoggingIn();
18 |
19 | User._handleLoginCallback(err, result);
20 |
21 | callback(err);
22 | });
23 | },
24 | changePassword(oldPassword, newPassword, callback = ()=>{}) {
25 |
26 | //TODO check Meteor.user() to prevent if not logged
27 |
28 | if(typeof newPassword != 'string' || !newPassword) {
29 | return callback("Password may not be empty");
30 | }
31 |
32 | call("changePassword",
33 | oldPassword ? hashPassword(oldPassword) : null,
34 | hashPassword(newPassword),
35 | (err, res) => {
36 |
37 | callback(err);
38 | });
39 | },
40 | forgotPassword(options, callback = ()=>{}) {
41 | if (!options.email) {
42 | return callback("Must pass options.email");
43 | }
44 |
45 | call("forgotPassword", options, err => {
46 | callback(err);
47 | });
48 | },
49 | onLogin(cb) {
50 | Data.on('onLogin', cb);
51 | },
52 | onLoginFailure(cb) {
53 | Data.on('onLoginFailure', cb);
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/Data.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import minimongo from 'minimongo-cache';
3 | process.nextTick = setImmediate;
4 |
5 | const db = new minimongo();
6 | db.debug = false;
7 | //db.batchedUpdates = React.addons.batchedUpdates;
8 |
9 | export default {
10 | _endpoint: null,
11 | _options: null,
12 | ddp: null,
13 | subscriptions: {},
14 | db: db,
15 | calls: [],
16 |
17 | getUrl() {
18 | return this._endpoint.substring(0, this._endpoint.indexOf('/websocket'));
19 | },
20 |
21 | waitDdpReady(cb) {
22 | if(this.ddp) {
23 | cb();
24 | } else {
25 | setTimeout(()=>{
26 | this.waitDdpReady(cb);
27 | }, 10);
28 | }
29 | },
30 |
31 | _cbs: [],
32 | onChange(cb) {
33 | this.db.on('change', cb);
34 | this.ddp.on('connected', cb);
35 | this.ddp.on('disconnected', cb);
36 | this.on('loggingIn', cb);
37 | this.on('change', cb);
38 | },
39 | offChange(cb) {
40 | this.db.off('change', cb);
41 | this.ddp.off('connected', cb);
42 | this.ddp.off('disconnected', cb);
43 | this.off('loggingIn', cb);
44 | this.off('change', cb);
45 | },
46 | on(eventName, cb) {
47 | this._cbs.push({
48 | eventName: eventName,
49 | callback: cb
50 | });
51 | },
52 | off(eventName, cb) {
53 | this._cbs.splice(this._cbs.findIndex(_cb=>_cb.callback == cb && _cb.eventName == eventName), 1);
54 | },
55 | notify(eventName) {
56 | this._cbs.map(cb=>{
57 | if(cb.eventName == eventName && typeof cb.callback == 'function') {
58 | cb.callback();
59 | }
60 | });
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "electron-meteor",
3 | "version": "0.3.0",
4 | "description": "Full Meteor Client for Electron",
5 | "main": "dist/src/Meteor.js",
6 | "scripts": {
7 | "compile": "npm run compilesrc && npm run compilelib",
8 | "watch": "npm run compilelib && ./node_modules/babel-cli/bin/babel.js -d dist/src src/ -w",
9 | "compilesrc": "./node_modules/babel-cli/bin/babel.js -d dist/src src/",
10 | "compilelib": "./node_modules/babel-cli/bin/babel.js -d dist/lib lib/",
11 | "prepublish": "npm run compile"
12 | },
13 | "repository": {
14 | "type": "git",
15 | "url": "git+https://github.com/inProgress-team/electron-meteor.git"
16 | },
17 | "keywords": [
18 | "react-component",
19 | "ddp",
20 | "meteor",
21 | "react",
22 | "electron"
23 | ],
24 | "author": "Théo Mathieu",
25 | "license": "MIT",
26 | "bugs": {
27 | "url": "https://github.com/inProgress-team/electron-meteor/issues"
28 | },
29 | "homepage": "https://github.com/inProgress-team/electron-meteor#readme",
30 | "dependencies": {
31 | "base-64": "^0.1.0",
32 | "crypto-js": "^3.1.6",
33 | "ejson": "^2.1.2",
34 | "electron-json-storage": "^2.0.0",
35 | "minimongo-cache": "0.0.48",
36 | "react": "^0.14.0 || ^15.0.1",
37 | "react-mixin": "^3.0.3",
38 | "trackr": "^2.0.2",
39 | "wolfy87-eventemitter": "^4.3.0"
40 | },
41 | "devDependencies": {
42 | "babel-cli": "^6.8.0",
43 | "babel-loader": "^6.2.4",
44 | "babel-plugin-transform-runtime": "^6.8.0",
45 | "babel-polyfill": "^6.8.0",
46 | "babel-preset-es2015": "^6.6.0",
47 | "babel-preset-react": "^6.5.0",
48 | "babel-preset-stage-0": "^6.5.0"
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/dist/lib/queue.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 |
7 | var _classCallCheck2 = require("babel-runtime/helpers/classCallCheck");
8 |
9 | var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
10 |
11 | var _createClass2 = require("babel-runtime/helpers/createClass");
12 |
13 | var _createClass3 = _interopRequireDefault(_createClass2);
14 |
15 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
16 |
17 | var Queue = function () {
18 |
19 | /*
20 | * As the name implies, `consumer` is the (sole) consumer of the queue.
21 | * It gets called with each element of the queue and its return value
22 | * serves as a ack, determining whether the element is removed or not from
23 | * the queue, allowing then subsequent elements to be processed.
24 | */
25 |
26 | function Queue(consumer) {
27 | (0, _classCallCheck3.default)(this, Queue);
28 |
29 | this.consumer = consumer;
30 | this.queue = [];
31 | }
32 |
33 | (0, _createClass3.default)(Queue, [{
34 | key: "push",
35 | value: function push(element) {
36 | this.queue.push(element);
37 | this.process();
38 | }
39 | }, {
40 | key: "process",
41 | value: function process() {
42 | if (this.queue.length !== 0) {
43 | var ack = this.consumer(this.queue[0]);
44 | if (ack) {
45 | this.queue.shift();
46 | this.process();
47 | }
48 | }
49 | }
50 | }, {
51 | key: "empty",
52 | value: function empty() {
53 | this.queue = [];
54 | }
55 | }]);
56 | return Queue;
57 | }();
58 |
59 | exports.default = Queue;
--------------------------------------------------------------------------------
/src/CollectionFS/setProperties.js:
--------------------------------------------------------------------------------
1 |
2 | import base64 from 'base-64';
3 | import Data from '../Data';
4 |
5 | export default (name, file)=> {
6 | const getStoreName = (params = {store: name}) => {
7 | return params.store;
8 | };
9 | const getImageInfos = params => {
10 | if(!params || !params.store) return file.original || {};
11 | return file.copies[params.store] || {};
12 | };
13 | const getType = params => {
14 | return getImageInfos(params).type;
15 | };
16 | return {
17 | ...file,
18 | url: params => {
19 | const token = Data._tokenIdSaved;
20 | const fileName = getImageInfos(params).name;
21 | return Data.getUrl().replace('ws://', 'http://').replace('wss://', 'https://')+'/cfs/files/'+name+'/'+file._id+'/'+fileName+'?store='+getStoreName(params)+(token ? '&token='+base64.encode(JSON.stringify({authToken: token})) : "");
22 | },
23 | isImage: params => {
24 | const type = getType(params);
25 | return type && type.indexOf('image/')===0;
26 | },
27 | isAudio: params => {
28 | const type = getType(params);
29 | return type && type.indexOf('audio/')===0;
30 | },
31 | isVideo: params => {
32 | const type = getType(params);
33 | return type && type.indexOf('video/')===0;
34 | },
35 | isUploaded: params => {
36 | return !!(getImageInfos(params).updatedAt);
37 | },
38 | name: params => {
39 | return getImageInfos(params).name;
40 | },
41 | extension: params => {
42 | const imageName = getImageInfos(params).name;
43 | if(!imageName) return;
44 | return imageName.substring(imageName.lastIndexOf('.')+1);
45 | },
46 | size: params => {
47 | return getImageInfos(params).size;
48 | },
49 | type: getType,
50 | updatedAt: params=>{
51 | return getImageInfos(params).updatedAt;
52 | }
53 | }
54 | }
--------------------------------------------------------------------------------
/dist/components/createContainer.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 | exports.default = undefined;
7 |
8 | var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; /**
9 | * Container helper using react-meteor-data.
10 | */
11 |
12 | var _react = require('react');
13 |
14 | var _react2 = _interopRequireDefault(_react);
15 |
16 | var _Mixin = require('./Mixin');
17 |
18 | var _Mixin2 = _interopRequireDefault(_Mixin);
19 |
20 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
21 |
22 | function createContainer() {
23 | var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
24 | var Component = arguments[1];
25 |
26 | var expandedOptions = options;
27 | if (typeof options === 'function') {
28 | expandedOptions = {
29 | getMeteorData: options
30 | };
31 | }
32 |
33 | var _expandedOptions = expandedOptions;
34 | var _getMeteorData = _expandedOptions.getMeteorData;
35 |
36 |
37 | return _react2.default.createClass({
38 | displayName: 'MeteorDataContainer',
39 | mixins: [_Mixin2.default],
40 | getMeteorData: function getMeteorData() {
41 | return _getMeteorData(this.props);
42 | },
43 | render: function render() {
44 | return _react2.default.createElement(Component, _extends({}, this.props, this.data));
45 | }
46 | });
47 | }
48 | exports.default = createContainer;
--------------------------------------------------------------------------------
/dist/src/Data.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 |
7 | var _react = require('react');
8 |
9 | var _react2 = _interopRequireDefault(_react);
10 |
11 | var _minimongoCache = require('minimongo-cache');
12 |
13 | var _minimongoCache2 = _interopRequireDefault(_minimongoCache);
14 |
15 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
16 |
17 | process.nextTick = setImmediate;
18 |
19 | var db = new _minimongoCache2.default();
20 | db.debug = false;
21 | //db.batchedUpdates = React.addons.batchedUpdates;
22 |
23 | exports.default = {
24 | _endpoint: null,
25 | _options: null,
26 | ddp: null,
27 | subscriptions: {},
28 | db: db,
29 | calls: [],
30 |
31 | getUrl: function getUrl() {
32 | return this._endpoint.substring(0, this._endpoint.indexOf('/websocket'));
33 | },
34 | waitDdpReady: function waitDdpReady(cb) {
35 | var _this = this;
36 |
37 | if (this.ddp) {
38 | cb();
39 | } else {
40 | setTimeout(function () {
41 | _this.waitDdpReady(cb);
42 | }, 10);
43 | }
44 | },
45 |
46 |
47 | _cbs: [],
48 | onChange: function onChange(cb) {
49 | this.db.on('change', cb);
50 | this.ddp.on('connected', cb);
51 | this.ddp.on('disconnected', cb);
52 | this.on('loggingIn', cb);
53 | this.on('change', cb);
54 | },
55 | offChange: function offChange(cb) {
56 | this.db.off('change', cb);
57 | this.ddp.off('connected', cb);
58 | this.ddp.off('disconnected', cb);
59 | this.off('loggingIn', cb);
60 | this.off('change', cb);
61 | },
62 | on: function on(eventName, cb) {
63 | this._cbs.push({
64 | eventName: eventName,
65 | callback: cb
66 | });
67 | },
68 | off: function off(eventName, cb) {
69 | this._cbs.splice(this._cbs.findIndex(function (_cb) {
70 | return _cb.callback == cb && _cb.eventName == eventName;
71 | }), 1);
72 | },
73 | notify: function notify(eventName) {
74 | this._cbs.map(function (cb) {
75 | if (cb.eventName == eventName && typeof cb.callback == 'function') {
76 | cb.callback();
77 | }
78 | });
79 | }
80 | };
--------------------------------------------------------------------------------
/dist/Data.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 |
7 | var _reactNative = require('react-native');
8 |
9 | var _reactNative2 = _interopRequireDefault(_reactNative);
10 |
11 | var _minimongoCache = require('minimongo-cache');
12 |
13 | var _minimongoCache2 = _interopRequireDefault(_minimongoCache);
14 |
15 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
16 |
17 | process.nextTick = setImmediate;
18 |
19 | var db = new _minimongoCache2.default();
20 | db.debug = false;
21 | db.batchedUpdates = _reactNative2.default.addons.batchedUpdates;
22 |
23 | exports.default = {
24 | _endpoint: null,
25 | _options: null,
26 | ddp: null,
27 | subscriptions: {},
28 | db: db,
29 | calls: [],
30 |
31 | getUrl: function getUrl() {
32 | return this._endpoint.substring(0, this._endpoint.indexOf('/websocket'));
33 | },
34 | waitDdpReady: function waitDdpReady(cb) {
35 | var _this = this;
36 |
37 | if (this.ddp) {
38 | cb();
39 | } else {
40 | setTimeout(function () {
41 | _this.waitDdpReady(cb);
42 | }, 10);
43 | }
44 | },
45 |
46 |
47 | _cbs: [],
48 | onChange: function onChange(cb) {
49 | this.db.on('change', cb);
50 | this.ddp.on('connected', cb);
51 | this.ddp.on('disconnected', cb);
52 | this.on('loggingIn', cb);
53 | this.on('change', cb);
54 | },
55 | offChange: function offChange(cb) {
56 | this.db.off('change', cb);
57 | this.ddp.off('connected', cb);
58 | this.ddp.off('disconnected', cb);
59 | this.off('loggingIn', cb);
60 | this.off('change', cb);
61 | },
62 | on: function on(eventName, cb) {
63 | this._cbs.push({
64 | eventName: eventName,
65 | callback: cb
66 | });
67 | },
68 | off: function off(eventName, cb) {
69 | this._cbs.splice(this._cbs.findIndex(function (_cb) {
70 | return _cb.callback == cb && _cb.eventName == eventName;
71 | }), 1);
72 | },
73 | notify: function notify(eventName) {
74 | this._cbs.map(function (cb) {
75 | if (cb.eventName == eventName && typeof cb.callback == 'function') {
76 | cb.callback();
77 | }
78 | });
79 | }
80 | };
--------------------------------------------------------------------------------
/dist/CollectionFS/FSCollection.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 |
7 | exports.default = function (name) {
8 | var Meteor = this;
9 | var collectionName = 'cfs.' + name + '.filerecord';
10 |
11 | return {
12 | find: function find(selector, options) {
13 | var elems = (0, _Collection2.default)(collectionName).find(selector, options);
14 | return elems.map(function (elem) {
15 | return (0, _setProperties2.default)(name, elem);
16 | });
17 | },
18 | findOne: function findOne(selector, options) {
19 | var elem = (0, _Collection2.default)(collectionName).findOne(selector, options);
20 | return elem && (0, _setProperties2.default)(name, elem);
21 | },
22 |
23 | insert: function insert() {
24 | _Collection2.default.apply(Meteor, [collectionName]).insert.apply(Meteor, arguments);
25 | },
26 | update: function update() {
27 | _Collection2.default.apply(Meteor, [collectionName]).update.apply(Meteor, arguments);
28 | },
29 | remove: function remove() {
30 | _Collection2.default.apply(Meteor, [collectionName]).remove.apply(Meteor, arguments);
31 | }
32 | };
33 | };
34 |
35 | var _ejson = require('ejson');
36 |
37 | var _ejson2 = _interopRequireDefault(_ejson);
38 |
39 | var _Collection = require('../Collection');
40 |
41 | var _Collection2 = _interopRequireDefault(_Collection);
42 |
43 | var _Data = require('../Data');
44 |
45 | var _Data2 = _interopRequireDefault(_Data);
46 |
47 | var _setProperties = require('./setProperties');
48 |
49 | var _setProperties2 = _interopRequireDefault(_setProperties);
50 |
51 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
52 |
53 | if (!_ejson2.default._getTypes()['FS.File']) {
54 | _ejson2.default.addType('FS.File', function (value) {
55 | return {
56 | getFileRecord: function getFileRecord() {
57 | var collection = _Data2.default.db['cfs.' + value.collectionName + '.filerecord'];
58 |
59 | var item = collection && collection.get(value._id);
60 |
61 | if (!item) return value;
62 |
63 | return (0, _setProperties2.default)(value.collectionName, item);
64 | }
65 | };
66 | });
67 | }
--------------------------------------------------------------------------------
/dist/src/CollectionFS/FSCollection.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 |
7 | exports.default = function (name) {
8 | var Meteor = this;
9 | var collectionName = 'cfs.' + name + '.filerecord';
10 |
11 | return {
12 | find: function find(selector, options) {
13 | var elems = (0, _Collection2.default)(collectionName).find(selector, options);
14 | return elems.map(function (elem) {
15 | return (0, _setProperties2.default)(name, elem);
16 | });
17 | },
18 | findOne: function findOne(selector, options) {
19 | var elem = (0, _Collection2.default)(collectionName).findOne(selector, options);
20 | return elem && (0, _setProperties2.default)(name, elem);
21 | },
22 |
23 | insert: function insert() {
24 | _Collection2.default.apply(Meteor, [collectionName]).insert.apply(Meteor, arguments);
25 | },
26 | update: function update() {
27 | _Collection2.default.apply(Meteor, [collectionName]).update.apply(Meteor, arguments);
28 | },
29 | remove: function remove() {
30 | _Collection2.default.apply(Meteor, [collectionName]).remove.apply(Meteor, arguments);
31 | }
32 | };
33 | };
34 |
35 | var _ejson = require('ejson');
36 |
37 | var _ejson2 = _interopRequireDefault(_ejson);
38 |
39 | var _Collection = require('../Collection');
40 |
41 | var _Collection2 = _interopRequireDefault(_Collection);
42 |
43 | var _Data = require('../Data');
44 |
45 | var _Data2 = _interopRequireDefault(_Data);
46 |
47 | var _setProperties = require('./setProperties');
48 |
49 | var _setProperties2 = _interopRequireDefault(_setProperties);
50 |
51 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
52 |
53 | if (!_ejson2.default._getTypes()['FS.File']) {
54 | _ejson2.default.addType('FS.File', function (value) {
55 | return {
56 | getFileRecord: function getFileRecord() {
57 | var collection = _Data2.default.db['cfs.' + value.collectionName + '.filerecord'];
58 |
59 | var item = collection && collection.get(value._id);
60 |
61 | if (!item) return value;
62 |
63 | return (0, _setProperties2.default)(value.collectionName, item);
64 | }
65 | };
66 | });
67 | }
--------------------------------------------------------------------------------
/dist/user/Accounts.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var _Data = require('../Data');
4 |
5 | var _Data2 = _interopRequireDefault(_Data);
6 |
7 | var _Call = require('../Call');
8 |
9 | var _Call2 = _interopRequireDefault(_Call);
10 |
11 | var _User = require('./User');
12 |
13 | var _User2 = _interopRequireDefault(_User);
14 |
15 | var _utils = require('../../lib/utils');
16 |
17 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
18 |
19 | module.exports = {
20 | createUser: function createUser(options) {
21 | var callback = arguments.length <= 1 || arguments[1] === undefined ? function () {} : arguments[1];
22 |
23 | if (options.username) options.username = options.username;
24 | if (options.email) options.email = options.email;
25 |
26 | // Replace password with the hashed password.
27 | options.password = (0, _utils.hashPassword)(options.password);
28 |
29 | _User2.default._startLoggingIn();
30 | (0, _Call2.default)("createUser", options, function (err, result) {
31 | _User2.default._endLoggingIn();
32 |
33 | _User2.default._handleLoginCallback(err, result);
34 |
35 | callback(err);
36 | });
37 | },
38 | changePassword: function changePassword(oldPassword, newPassword) {
39 | var callback = arguments.length <= 2 || arguments[2] === undefined ? function () {} : arguments[2];
40 |
41 |
42 | //TODO check Meteor.user() to prevent if not logged
43 |
44 | if (typeof newPassword != 'string' || !newPassword) {
45 | return callback("Password may not be empty");
46 | }
47 |
48 | (0, _Call2.default)("changePassword", oldPassword ? (0, _utils.hashPassword)(oldPassword) : null, (0, _utils.hashPassword)(newPassword), function (err, res) {
49 |
50 | callback(err);
51 | });
52 | },
53 | forgotPassword: function forgotPassword(options) {
54 | var callback = arguments.length <= 1 || arguments[1] === undefined ? function () {} : arguments[1];
55 |
56 | if (!options.email) {
57 | return callback("Must pass options.email");
58 | }
59 |
60 | (0, _Call2.default)("forgotPassword", options, function (err) {
61 | callback(err);
62 | });
63 | },
64 | onLogin: function onLogin(cb) {
65 | _Data2.default.on('onLogin', cb);
66 | },
67 | onLoginFailure: function onLoginFailure(cb) {
68 | _Data2.default.on('onLoginFailure', cb);
69 | }
70 | };
--------------------------------------------------------------------------------
/dist/src/user/Accounts.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var _Data = require('../Data');
4 |
5 | var _Data2 = _interopRequireDefault(_Data);
6 |
7 | var _Call = require('../Call');
8 |
9 | var _Call2 = _interopRequireDefault(_Call);
10 |
11 | var _User = require('./User');
12 |
13 | var _User2 = _interopRequireDefault(_User);
14 |
15 | var _utils = require('../../lib/utils');
16 |
17 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
18 |
19 | module.exports = {
20 | createUser: function createUser(options) {
21 | var callback = arguments.length <= 1 || arguments[1] === undefined ? function () {} : arguments[1];
22 |
23 | if (options.username) options.username = options.username;
24 | if (options.email) options.email = options.email;
25 |
26 | // Replace password with the hashed password.
27 | options.password = (0, _utils.hashPassword)(options.password);
28 |
29 | _User2.default._startLoggingIn();
30 | (0, _Call2.default)("createUser", options, function (err, result) {
31 | _User2.default._endLoggingIn();
32 |
33 | _User2.default._handleLoginCallback(err, result);
34 |
35 | callback(err);
36 | });
37 | },
38 | changePassword: function changePassword(oldPassword, newPassword) {
39 | var callback = arguments.length <= 2 || arguments[2] === undefined ? function () {} : arguments[2];
40 |
41 |
42 | //TODO check Meteor.user() to prevent if not logged
43 |
44 | if (typeof newPassword != 'string' || !newPassword) {
45 | return callback("Password may not be empty");
46 | }
47 |
48 | (0, _Call2.default)("changePassword", oldPassword ? (0, _utils.hashPassword)(oldPassword) : null, (0, _utils.hashPassword)(newPassword), function (err, res) {
49 |
50 | callback(err);
51 | });
52 | },
53 | forgotPassword: function forgotPassword(options) {
54 | var callback = arguments.length <= 1 || arguments[1] === undefined ? function () {} : arguments[1];
55 |
56 | if (!options.email) {
57 | return callback("Must pass options.email");
58 | }
59 |
60 | (0, _Call2.default)("forgotPassword", options, function (err) {
61 | callback(err);
62 | });
63 | },
64 | onLogin: function onLogin(cb) {
65 | _Data2.default.on('onLogin', cb);
66 | },
67 | onLoginFailure: function onLoginFailure(cb) {
68 | _Data2.default.on('onLoginFailure', cb);
69 | }
70 | };
--------------------------------------------------------------------------------
/dist/src/CollectionFS/setProperties.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 |
7 | var _extends2 = require('babel-runtime/helpers/extends');
8 |
9 | var _extends3 = _interopRequireDefault(_extends2);
10 |
11 | var _base = require('base-64');
12 |
13 | var _base2 = _interopRequireDefault(_base);
14 |
15 | var _Data = require('../Data');
16 |
17 | var _Data2 = _interopRequireDefault(_Data);
18 |
19 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
20 |
21 | exports.default = function (name, file) {
22 | var getStoreName = function getStoreName() {
23 | var params = arguments.length <= 0 || arguments[0] === undefined ? { store: name } : arguments[0];
24 |
25 | return params.store;
26 | };
27 | var getImageInfos = function getImageInfos(params) {
28 | if (!params || !params.store) return file.original || {};
29 | return file.copies[params.store] || {};
30 | };
31 | var getType = function getType(params) {
32 | return getImageInfos(params).type;
33 | };
34 | return (0, _extends3.default)({}, file, {
35 | url: function url(params) {
36 | var token = _Data2.default._tokenIdSaved;
37 | var fileName = getImageInfos(params).name;
38 | return _Data2.default.getUrl().replace('ws://', 'http://').replace('wss://', 'https://') + '/cfs/files/' + name + '/' + file._id + '/' + fileName + '?store=' + getStoreName(params) + (token ? '&token=' + _base2.default.encode(JSON.stringify({ authToken: token })) : "");
39 | },
40 | isImage: function isImage(params) {
41 | var type = getType(params);
42 | return type && type.indexOf('image/') === 0;
43 | },
44 | isAudio: function isAudio(params) {
45 | var type = getType(params);
46 | return type && type.indexOf('audio/') === 0;
47 | },
48 | isVideo: function isVideo(params) {
49 | var type = getType(params);
50 | return type && type.indexOf('video/') === 0;
51 | },
52 | isUploaded: function isUploaded(params) {
53 | return !!getImageInfos(params).updatedAt;
54 | },
55 | name: function name(params) {
56 | return getImageInfos(params).name;
57 | },
58 | extension: function extension(params) {
59 | var imageName = getImageInfos(params).name;
60 | if (!imageName) return;
61 | return imageName.substring(imageName.lastIndexOf('.') + 1);
62 | },
63 | size: function size(params) {
64 | return getImageInfos(params).size;
65 | },
66 | type: getType,
67 | updatedAt: function updatedAt(params) {
68 | return getImageInfos(params).updatedAt;
69 | }
70 | });
71 | };
--------------------------------------------------------------------------------
/dist/CollectionFS/setProperties.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 |
7 | var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
8 |
9 | var _base = require('base-64');
10 |
11 | var _base2 = _interopRequireDefault(_base);
12 |
13 | var _Data = require('../Data');
14 |
15 | var _Data2 = _interopRequireDefault(_Data);
16 |
17 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
18 |
19 | exports.default = function (name, file) {
20 | var getStoreName = function getStoreName() {
21 | var params = arguments.length <= 0 || arguments[0] === undefined ? { store: name } : arguments[0];
22 |
23 | return params.store;
24 | };
25 | var getImageInfos = function getImageInfos(params) {
26 | if (!params || !params.store) return file.original || {};
27 | return file.copies[params.store] || {};
28 | };
29 | var getType = function getType(params) {
30 | return getImageInfos(params).type;
31 | };
32 | return _extends({}, file, {
33 | url: function url(params) {
34 | var token = _Data2.default._tokenIdSaved;
35 | var fileName = getImageInfos(params).name;
36 | return _Data2.default.getUrl().replace('ws://', 'http://').replace('wss://', 'https://') + '/cfs/files/' + name + '/' + file._id + '/' + fileName + '?store=' + getStoreName(params) + (token ? '&token=' + _base2.default.encode(JSON.stringify({ authToken: token })) : "");
37 | },
38 | isImage: function isImage(params) {
39 | var type = getType(params);
40 | return type && type.indexOf('image/') === 0;
41 | },
42 | isAudio: function isAudio(params) {
43 | var type = getType(params);
44 | return type && type.indexOf('audio/') === 0;
45 | },
46 | isVideo: function isVideo(params) {
47 | var type = getType(params);
48 | return type && type.indexOf('video/') === 0;
49 | },
50 | isUploaded: function isUploaded(params) {
51 | return !!getImageInfos(params).updatedAt;
52 | },
53 | name: function name(params) {
54 | return getImageInfos(params).name;
55 | },
56 | extension: function extension(params) {
57 | var imageName = getImageInfos(params).name;
58 | if (!imageName) return;
59 | return imageName.substring(imageName.lastIndexOf('.') + 1);
60 | },
61 | size: function size(params) {
62 | return getImageInfos(params).size;
63 | },
64 | type: getType,
65 | updatedAt: function updatedAt(params) {
66 | return getImageInfos(params).updatedAt;
67 | }
68 | });
69 | };
--------------------------------------------------------------------------------
/src/Collection.js:
--------------------------------------------------------------------------------
1 | import Data from './Data';
2 | import Random from '../lib/Random';
3 |
4 | export default function(name) {
5 | const Meteor = this;
6 | if(!Data.db[name]) { Data.db.addCollection(name) }
7 |
8 | return {
9 | find(selector, options) {
10 | if(typeof selector == 'string') {
11 | if(options) {
12 | return [Data.db[name].findOne({_id: selector}, options)];
13 | } else {
14 | return [Data.db[name].get(selector)];
15 | }
16 | }
17 | return Data.db[name].find(selector, options);
18 |
19 | },
20 | findOne(selector, options) {
21 |
22 | if(typeof selector == 'string') {
23 | if(options) {
24 | return Data.db[name].findOne({_id: selector}, options);
25 | } else {
26 | return Data.db[name].get(selector);
27 | }
28 | }
29 | return Data.db[name] && Data.db[name].findOne(selector, options)
30 |
31 | },
32 | insert(item, callback = ()=>{}) {
33 |
34 | let id;
35 |
36 | if('_id' in item) {
37 | if(!item._id || typeof item._id != 'string') {
38 | return callback("Meteor requires document _id fields to be non-empty strings");
39 | }
40 | id = item._id;
41 | } else {
42 | id = item._id = Random.id();
43 | }
44 |
45 | if(Data.db[name].get(id)) return callback({error: 409, reason: "Duplicate key _id with value "+id});
46 |
47 |
48 | Data.db[name].upsert(item);
49 |
50 | Meteor.waitDdpConnected(()=>{
51 | Meteor.call('/'+name+'/insert', item, err => {
52 | if(err) {
53 | Data.db[name].del(id);
54 | return callback(err);
55 | }
56 |
57 | callback(null, id);
58 | });
59 | });
60 |
61 |
62 | return id;
63 | },
64 | update(id, modifier, options={}, callback=()=>{}) {
65 |
66 | if(typeof options == 'function') {
67 | callback = options;
68 | options = {};
69 | }
70 |
71 | if(!Data.db[name].get(id)) return callback({error: 409, reason: "Item not found in collection "+name+" with id "+id});
72 |
73 | Meteor.waitDdpConnected(()=>{
74 | Meteor.call('/'+name+'/update', {_id: id}, modifier, err => {
75 | if(err) {
76 | return callback(err);
77 | }
78 |
79 | callback(null, id);
80 | });
81 | });
82 | },
83 | remove(id, callback = ()=>{}) {
84 |
85 | const element = this.findOne(id);
86 | if(element) {
87 | Data.db[name].del(element._id);
88 |
89 | Meteor.waitDdpConnected(()=>{
90 | Meteor.call('/'+name+'/remove', {_id: id}, (err, res) => {
91 | if(err) {
92 | Data.db[name].upsert(element);
93 | return callback(err);
94 | }
95 | callback(null, res);
96 |
97 | });
98 | });
99 |
100 | } else {
101 | callback('No document with _id : ' + id);
102 | }
103 | }
104 | };
105 | }
--------------------------------------------------------------------------------
/src/user/User.js:
--------------------------------------------------------------------------------
1 | //import { AsyncStorage } from 'react-native';
2 | import storage from 'electron-json-storage';
3 |
4 | import Data from '../Data';
5 | import { hashPassword } from '../../lib/utils';
6 |
7 | const TOKEN_KEY = 'reactnativemeteor_usertoken';
8 |
9 | module.exports = {
10 | user() {
11 | if(!this._userIdSaved) return null;
12 |
13 | return this.collection('users').findOne(this._userIdSaved);
14 | },
15 | userId() {
16 | if(!this._userIdSaved) return null;
17 |
18 | const user = this.collection('users').findOne(this._userIdSaved);
19 | return user && user._id;
20 | },
21 | _isLoggingIn: true,
22 | loggingIn() {
23 | return this._isLoggingIn;
24 | },
25 | logout(callback) {
26 | this.call("logout", err => {
27 | this.handleLogout();
28 | this.connect();
29 |
30 | typeof callback == 'function' && callback(err);
31 | });
32 | },
33 | handleLogout() {
34 | storage.remove(TOKEN_KEY);
35 | Data._tokenIdSaved = null;
36 | this._userIdSaved = null;
37 | },
38 | loginWithPassword(selector, password, callback) {
39 | if (typeof selector === 'string') {
40 | if (selector.indexOf('@') === -1)
41 | selector = {username: selector};
42 | else
43 | selector = {email: selector};
44 | }
45 |
46 | this._startLoggingIn();
47 | this.call("login", {
48 | user: selector,
49 | password: hashPassword(password)
50 | }, (err, result)=>{
51 | this._endLoggingIn();
52 |
53 | this._handleLoginCallback(err, result);
54 |
55 | typeof callback == 'function' && callback(err);
56 | });
57 | },
58 | logoutOtherClients(callback = ()=>{}) {
59 | this.call('getNewToken', (err, res) => {
60 | if(err) return callback(err);
61 |
62 | this._handleLoginCallback(err, res);
63 |
64 | this.call('removeOtherTokens', err=>{
65 | callback(err);
66 | })
67 | });
68 | },
69 | _startLoggingIn() {
70 | this._isLoggingIn = true;
71 | Data.notify('loggingIn');
72 | },
73 | _endLoggingIn() {
74 | this._isLoggingIn = false;
75 | Data.notify('loggingIn');
76 | },
77 | _handleLoginCallback(err, result) {
78 | if(!err) {//save user id and token
79 | storage.set(TOKEN_KEY, {token: result.token});
80 | Data._tokenIdSaved = result.token;
81 | this._userIdSaved = result.id;
82 | Data.notify('onLogin');
83 | } else {
84 | Data.notify('onLoginFailure');
85 | this.handleLogout();
86 | }
87 | Data.notify('change');
88 | },
89 | async _loadInitialUser() {
90 | var value = null;
91 |
92 | try {
93 | const getStorage = function() {
94 | return new Promise(function(resolve, reject) {
95 | storage.get(TOKEN_KEY, function(err, res) {
96 | resolve(res)
97 | });
98 | })
99 | }
100 | value = await getStorage();
101 | value = value.token;
102 | } catch (error) {
103 | console.warn('json-storage error: ' + error.message);
104 | } finally {
105 | Data._tokenIdSaved = value;
106 | if (value !== null){
107 | this._startLoggingIn();
108 | this.call('login', { resume: value }, (err, result) => {
109 | this._endLoggingIn();
110 | this._handleLoginCallback(err, result);
111 | });
112 | } else {
113 | this._endLoggingIn();
114 | }
115 | }
116 |
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/dist/src/CollectionFS/FSCollectionImagesPreloader.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 |
7 | var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
8 |
9 | var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
10 |
11 | var _createClass2 = require('babel-runtime/helpers/createClass');
12 |
13 | var _createClass3 = _interopRequireDefault(_createClass2);
14 |
15 | var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn');
16 |
17 | var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
18 |
19 | var _inherits2 = require('babel-runtime/helpers/inherits');
20 |
21 | var _inherits3 = _interopRequireDefault(_inherits2);
22 |
23 | var _react = require('react');
24 |
25 | var _react2 = _interopRequireDefault(_react);
26 |
27 | var _Data = require('../Data');
28 |
29 | var _Data2 = _interopRequireDefault(_Data);
30 |
31 | var _setProperties = require('./setProperties');
32 |
33 | var _setProperties2 = _interopRequireDefault(_setProperties);
34 |
35 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
36 |
37 | var FSCollectionImagesPreloader = function (_Component) {
38 | (0, _inherits3.default)(FSCollectionImagesPreloader, _Component);
39 |
40 | function FSCollectionImagesPreloader(props) {
41 | (0, _classCallCheck3.default)(this, FSCollectionImagesPreloader);
42 |
43 | var _this = (0, _possibleConstructorReturn3.default)(this, Object.getPrototypeOf(FSCollectionImagesPreloader).call(this, props));
44 |
45 | _this.state = {
46 | items: []
47 | };
48 | return _this;
49 | }
50 |
51 | (0, _createClass3.default)(FSCollectionImagesPreloader, [{
52 | key: 'componentWillMount',
53 | value: function componentWillMount() {
54 | var _this2 = this;
55 |
56 | var _props = this.props;
57 | var collection = _props.collection;
58 | var selector = _props.selector;
59 |
60 |
61 | this.update = function (results) {
62 | _this2.setState({
63 | items: results.map(function (elem) {
64 | return (0, _setProperties2.default)(collection, elem);
65 | })
66 | });
67 | };
68 |
69 | var collectionName = 'cfs.' + collection + '.filerecord';
70 |
71 | if (!_Data2.default.db[collectionName]) {
72 | _Data2.default.db.addCollection(collectionName);
73 | }
74 |
75 | this.items = _Data2.default.db.observe(function () {
76 | return _Data2.default.db[collectionName].find(selector);
77 | });
78 |
79 | this.items.subscribe(this.update);
80 | }
81 | }, {
82 | key: 'componentWillUnmount',
83 | value: function componentWillUnmount() {
84 | this.items.dispose();
85 | }
86 | }, {
87 | key: 'render',
88 | value: function render() {
89 | var items = this.state.items;
90 |
91 |
92 | return _react2.default.createElement('img', { src: item.url(), style: { width: 1, height: 1, position: 'absolute', top: '-5000px', left: '-5000px' } });
93 | }
94 | }]);
95 | return FSCollectionImagesPreloader;
96 | }(_react.Component);
97 |
98 | FSCollectionImagesPreloader.propTypes = {
99 | collection: _react.PropTypes.string.isRequired,
100 | selector: _react.PropTypes.oneOfType([_react.PropTypes.string, _react.PropTypes.object])
101 | };
102 | FSCollectionImagesPreloader.defaultProps = {
103 | selector: {}
104 | };
105 | exports.default = FSCollectionImagesPreloader;
--------------------------------------------------------------------------------
/lib/socket.js:
--------------------------------------------------------------------------------
1 | import EventEmitter from "wolfy87-eventemitter";
2 | import EJSON from "ejson";
3 |
4 | export default class Socket extends EventEmitter {
5 |
6 | constructor (SocketConstructor, endpoint) {
7 | super();
8 | this.SocketConstructor = SocketConstructor;
9 | this.endpoint = endpoint;
10 | this.rawSocket = null;
11 | }
12 |
13 | send (object) {
14 | const message = EJSON.stringify(object);
15 | this.rawSocket.send(message);
16 | // Emit a copy of the object, as the listener might mutate it.
17 | this.emit("message:out", EJSON.parse(message));
18 | }
19 |
20 | open () {
21 |
22 | /*
23 | * Makes `open` a no-op if there's already a `rawSocket`. This avoids
24 | * memory / socket leaks if `open` is called twice (e.g. by a user
25 | * calling `ddp.connect` twice) without properly disposing of the
26 | * socket connection. `rawSocket` gets automatically set to `null` only
27 | * when it goes into a closed or error state. This way `rawSocket` is
28 | * disposed of correctly: the socket connection is closed, and the
29 | * object can be garbage collected.
30 | */
31 | if (this.rawSocket) {
32 | return;
33 | }
34 | this.rawSocket = new this.SocketConstructor(this.endpoint);
35 |
36 | /*
37 | * Calls to `onopen` and `onclose` directly trigger the `open` and
38 | * `close` events on the `Socket` instance.
39 | */
40 | this.rawSocket.onopen = () => this.emit("open");
41 | this.rawSocket.onclose = () => {
42 | this.rawSocket = null;
43 | this.emit("close");
44 | };
45 | /*
46 | * Calls to `onerror` trigger the `close` event on the `Socket`
47 | * instance, and cause the `rawSocket` object to be disposed of.
48 | * Since it's not clear what conditions could cause the error and if
49 | * it's possible to recover from it, we prefer to always close the
50 | * connection (if it isn't already) and dispose of the socket object.
51 | */
52 | this.rawSocket.onerror = () => {
53 | // It's not clear what the socket lifecycle is when errors occurr.
54 | // Hence, to avoid the `close` event to be emitted twice, before
55 | // manually closing the socket we de-register the `onclose`
56 | // callback.
57 | delete this.rawSocket.onclose;
58 | // Safe to perform even if the socket is already closed
59 | this.rawSocket.close();
60 | this.rawSocket = null;
61 | this.emit("close");
62 | };
63 | /*
64 | * Calls to `onmessage` trigger a `message:in` event on the `Socket`
65 | * instance only once the message (first parameter to `onmessage`) has
66 | * been successfully parsed into a javascript object.
67 | */
68 | this.rawSocket.onmessage = message => {
69 | var object;
70 | try {
71 | object = EJSON.parse(message.data);
72 | } catch (ignore) {
73 | // Simply ignore the malformed message and return
74 | return;
75 | }
76 | // Outside the try-catch block as it must only catch JSON parsing
77 | // errors, not errors that may occur inside a "message:in" event
78 | // handler
79 | this.emit("message:in", object);
80 | };
81 |
82 | }
83 |
84 | close () {
85 | /*
86 | * Avoid throwing an error if `rawSocket === null`
87 | */
88 | if (this.rawSocket) {
89 | this.rawSocket.close();
90 | }
91 | }
92 |
93 | }
--------------------------------------------------------------------------------
/dist/Collection.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 |
7 | exports.default = function (name) {
8 | var Meteor = this;
9 | if (!_Data2.default.db[name]) {
10 | _Data2.default.db.addCollection(name);
11 | }
12 |
13 | return {
14 | find: function find(selector, options) {
15 | if (typeof selector == 'string') {
16 | if (options) {
17 | return [_Data2.default.db[name].findOne({ _id: selector }, options)];
18 | } else {
19 | return [_Data2.default.db[name].get(selector)];
20 | }
21 | }
22 | return _Data2.default.db[name].find(selector, options);
23 | },
24 | findOne: function findOne(selector, options) {
25 |
26 | if (typeof selector == 'string') {
27 | if (options) {
28 | return _Data2.default.db[name].findOne({ _id: selector }, options);
29 | } else {
30 | return _Data2.default.db[name].get(selector);
31 | }
32 | }
33 | return _Data2.default.db[name] && _Data2.default.db[name].findOne(selector, options);
34 | },
35 | insert: function insert(item) {
36 | var callback = arguments.length <= 1 || arguments[1] === undefined ? function () {} : arguments[1];
37 |
38 |
39 | var id = void 0;
40 |
41 | if ('_id' in item) {
42 | if (!item._id || typeof item._id != 'string') {
43 | return callback("Meteor requires document _id fields to be non-empty strings");
44 | }
45 | id = item._id;
46 | } else {
47 | id = item._id = _Random2.default.id();
48 | }
49 |
50 | if (_Data2.default.db[name].get(id)) return callback({ error: 409, reason: "Duplicate key _id with value " + id });
51 |
52 | _Data2.default.db[name].upsert(item);
53 |
54 | Meteor.waitDdpConnected(function () {
55 | Meteor.call('/' + name + '/insert', item, function (err) {
56 | if (err) {
57 | _Data2.default.db[name].del(id);
58 | return callback(err);
59 | }
60 |
61 | callback(null, id);
62 | });
63 | });
64 |
65 | return id;
66 | },
67 | update: function update(id, modifier) {
68 | var options = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2];
69 | var callback = arguments.length <= 3 || arguments[3] === undefined ? function () {} : arguments[3];
70 |
71 |
72 | if (typeof options == 'function') {
73 | callback = options;
74 | options = {};
75 | }
76 |
77 | if (!_Data2.default.db[name].get(id)) return callback({ error: 409, reason: "Item not found in collection " + name + " with id " + id });
78 |
79 | Meteor.waitDdpConnected(function () {
80 | Meteor.call('/' + name + '/update', { _id: id }, modifier, function (err) {
81 | if (err) {
82 | return callback(err);
83 | }
84 |
85 | callback(null, id);
86 | });
87 | });
88 | },
89 | remove: function remove(id) {
90 | var callback = arguments.length <= 1 || arguments[1] === undefined ? function () {} : arguments[1];
91 |
92 |
93 | var element = this.findOne(id);
94 | if (element) {
95 | _Data2.default.db[name].del(element._id);
96 |
97 | Meteor.waitDdpConnected(function () {
98 | Meteor.call('/' + name + '/remove', { _id: id }, function (err, res) {
99 | if (err) {
100 | _Data2.default.db[name].upsert(element);
101 | return callback(err);
102 | }
103 | callback(null, res);
104 | });
105 | });
106 | } else {
107 | callback('No document with _id : ' + id);
108 | }
109 | }
110 | };
111 | };
112 |
113 | var _Data = require('./Data');
114 |
115 | var _Data2 = _interopRequireDefault(_Data);
116 |
117 | var _Random = require('../lib/Random');
118 |
119 | var _Random2 = _interopRequireDefault(_Random);
120 |
121 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
--------------------------------------------------------------------------------
/dist/src/Collection.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 |
7 | exports.default = function (name) {
8 | var Meteor = this;
9 | if (!_Data2.default.db[name]) {
10 | _Data2.default.db.addCollection(name);
11 | }
12 |
13 | return {
14 | find: function find(selector, options) {
15 | if (typeof selector == 'string') {
16 | if (options) {
17 | return [_Data2.default.db[name].findOne({ _id: selector }, options)];
18 | } else {
19 | return [_Data2.default.db[name].get(selector)];
20 | }
21 | }
22 | return _Data2.default.db[name].find(selector, options);
23 | },
24 | findOne: function findOne(selector, options) {
25 |
26 | if (typeof selector == 'string') {
27 | if (options) {
28 | return _Data2.default.db[name].findOne({ _id: selector }, options);
29 | } else {
30 | return _Data2.default.db[name].get(selector);
31 | }
32 | }
33 | return _Data2.default.db[name] && _Data2.default.db[name].findOne(selector, options);
34 | },
35 | insert: function insert(item) {
36 | var callback = arguments.length <= 1 || arguments[1] === undefined ? function () {} : arguments[1];
37 |
38 |
39 | var id = void 0;
40 |
41 | if ('_id' in item) {
42 | if (!item._id || typeof item._id != 'string') {
43 | return callback("Meteor requires document _id fields to be non-empty strings");
44 | }
45 | id = item._id;
46 | } else {
47 | id = item._id = _Random2.default.id();
48 | }
49 |
50 | if (_Data2.default.db[name].get(id)) return callback({ error: 409, reason: "Duplicate key _id with value " + id });
51 |
52 | _Data2.default.db[name].upsert(item);
53 |
54 | Meteor.waitDdpConnected(function () {
55 | Meteor.call('/' + name + '/insert', item, function (err) {
56 | if (err) {
57 | _Data2.default.db[name].del(id);
58 | return callback(err);
59 | }
60 |
61 | callback(null, id);
62 | });
63 | });
64 |
65 | return id;
66 | },
67 | update: function update(id, modifier) {
68 | var options = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2];
69 | var callback = arguments.length <= 3 || arguments[3] === undefined ? function () {} : arguments[3];
70 |
71 |
72 | if (typeof options == 'function') {
73 | callback = options;
74 | options = {};
75 | }
76 |
77 | if (!_Data2.default.db[name].get(id)) return callback({ error: 409, reason: "Item not found in collection " + name + " with id " + id });
78 |
79 | Meteor.waitDdpConnected(function () {
80 | Meteor.call('/' + name + '/update', { _id: id }, modifier, function (err) {
81 | if (err) {
82 | return callback(err);
83 | }
84 |
85 | callback(null, id);
86 | });
87 | });
88 | },
89 | remove: function remove(id) {
90 | var callback = arguments.length <= 1 || arguments[1] === undefined ? function () {} : arguments[1];
91 |
92 |
93 | var element = this.findOne(id);
94 | if (element) {
95 | _Data2.default.db[name].del(element._id);
96 |
97 | Meteor.waitDdpConnected(function () {
98 | Meteor.call('/' + name + '/remove', { _id: id }, function (err, res) {
99 | if (err) {
100 | _Data2.default.db[name].upsert(element);
101 | return callback(err);
102 | }
103 | callback(null, res);
104 | });
105 | });
106 | } else {
107 | callback('No document with _id : ' + id);
108 | }
109 | }
110 | };
111 | };
112 |
113 | var _Data = require('./Data');
114 |
115 | var _Data2 = _interopRequireDefault(_Data);
116 |
117 | var _Random = require('../lib/Random');
118 |
119 | var _Random2 = _interopRequireDefault(_Random);
120 |
121 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
--------------------------------------------------------------------------------
/lib/ddp.js:
--------------------------------------------------------------------------------
1 | /**
2 | * DDP.JS 2.1.0
3 | */
4 |
5 |
6 | import EventEmitter from "wolfy87-eventemitter";
7 | import Queue from "./queue";
8 | import Socket from "./socket";
9 | import {contains, uniqueId} from "./utils";
10 |
11 | const DDP_VERSION = "1";
12 | const PUBLIC_EVENTS = [
13 | // Subscription messages
14 | "ready", "nosub", "added", "changed", "removed",
15 | // Method messages
16 | "result", "updated",
17 | // Error messages
18 | "error"
19 | ];
20 | const DEFAULT_RECONNECT_INTERVAL = 10000;
21 |
22 | export default class DDP extends EventEmitter {
23 |
24 | emit () {
25 | setTimeout(super.emit.bind(this, ...arguments), 0);
26 | }
27 |
28 | constructor (options) {
29 |
30 | super();
31 |
32 | this.status = "disconnected";
33 |
34 | // Default `autoConnect` and `autoReconnect` to true
35 | this.autoConnect = (options.autoConnect !== false);
36 | this.autoReconnect = (options.autoReconnect !== false);
37 | this.reconnectInterval = options.reconnectInterval || DEFAULT_RECONNECT_INTERVAL;
38 |
39 | this.messageQueue = new Queue(message => {
40 | if (this.status === "connected") {
41 | this.socket.send(message);
42 | return true;
43 | } else {
44 | return false;
45 | }
46 | });
47 |
48 | this.socket = new Socket(options.SocketConstructor, options.endpoint);
49 |
50 | this.socket.on("open", () => {
51 | // When the socket opens, send the `connect` message
52 | // to establish the DDP connection
53 | this.socket.send({
54 | msg: "connect",
55 | version: DDP_VERSION,
56 | support: [DDP_VERSION]
57 | });
58 | });
59 |
60 | this.socket.on("close", () => {
61 | this.status = "disconnected";
62 | this.messageQueue.empty();
63 | this.emit("disconnected");
64 | if (this.autoReconnect) {
65 | // Schedule a reconnection
66 | setTimeout(
67 | this.socket.open.bind(this.socket),
68 | this.reconnectInterval
69 | );
70 | }
71 | });
72 |
73 | this.socket.on("message:in", message => {
74 | if (message.msg === "connected") {
75 | this.status = "connected";
76 | this.messageQueue.process();
77 | this.emit("connected");
78 | } else if (message.msg === "ping") {
79 | // Reply with a `pong` message to prevent the server from
80 | // closing the connection
81 | this.socket.send({msg: "pong", id: message.id});
82 | } else if (contains(PUBLIC_EVENTS, message.msg)) {
83 | this.emit(message.msg, message);
84 | }
85 | });
86 |
87 | if (this.autoConnect) {
88 | this.connect();
89 | }
90 |
91 | }
92 |
93 | connect () {
94 | this.socket.open();
95 | }
96 |
97 | disconnect () {
98 | /*
99 | * If `disconnect` is called, the caller likely doesn't want the
100 | * the instance to try to auto-reconnect. Therefore we set the
101 | * `autoReconnect` flag to false.
102 | */
103 | this.autoReconnect = false;
104 | this.socket.close();
105 | }
106 |
107 | method (name, params) {
108 | const id = uniqueId();
109 | this.messageQueue.push({
110 | msg: "method",
111 | id: id,
112 | method: name,
113 | params: params
114 | });
115 | return id;
116 | }
117 |
118 | sub (name, params) {
119 | const id = uniqueId();
120 | this.messageQueue.push({
121 | msg: "sub",
122 | id: id,
123 | name: name,
124 | params: params
125 | });
126 | return id;
127 | }
128 |
129 | unsub (id) {
130 | this.messageQueue.push({
131 | msg: "unsub",
132 | id: id
133 | });
134 | return id;
135 | }
136 |
137 | }
--------------------------------------------------------------------------------
/dist/components/ComplexListView.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 |
7 | var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
8 |
9 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
10 |
11 | var _reactNative = require('react-native');
12 |
13 | var _reactNative2 = _interopRequireDefault(_reactNative);
14 |
15 | var _Data = require('../Data');
16 |
17 | var _Data2 = _interopRequireDefault(_Data);
18 |
19 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
20 |
21 | function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
22 |
23 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
24 |
25 | function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
26 |
27 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
28 |
29 | var MeteorListView = function (_Component) {
30 | _inherits(MeteorListView, _Component);
31 |
32 | function MeteorListView(props) {
33 | _classCallCheck(this, MeteorListView);
34 |
35 | var _this = _possibleConstructorReturn(this, Object.getPrototypeOf(MeteorListView).call(this, props));
36 |
37 | _this.state = {
38 | ds: new _reactNative.ListView.DataSource({
39 | rowHasChanged: function rowHasChanged(row1, row2) {
40 | return row1 !== row2;
41 | }
42 | })
43 | };
44 | return _this;
45 | }
46 |
47 | _createClass(MeteorListView, [{
48 | key: 'componentWillReceiveProps',
49 | value: function componentWillReceiveProps(props) {
50 | var elements = props.elements;
51 |
52 |
53 | var elems = elements();
54 | this.setState({
55 | ds: this.state.ds.cloneWithRows(elems)
56 | });
57 | }
58 | }, {
59 | key: 'componentWillMount',
60 | value: function componentWillMount() {
61 | var _this2 = this;
62 |
63 | var elements = this.props.elements;
64 |
65 |
66 | this.onChange = function () {
67 | var elems = elements();
68 | _this2.setState({
69 | ds: _this2.state.ds.cloneWithRows(elems)
70 | });
71 | };
72 |
73 | this.onChange();
74 | _Data2.default.onChange(this.onChange);
75 | }
76 | }, {
77 | key: 'componentWillUnmount',
78 | value: function componentWillUnmount() {
79 | _Data2.default.offChange(this.onChange);
80 | }
81 | }, {
82 | key: 'render',
83 | value: function render() {
84 | var ds = this.state.ds;
85 | var _props = this.props;
86 | var listViewRef = _props.listViewRef;
87 |
88 | var props = _objectWithoutProperties(_props, ['listViewRef']);
89 |
90 | return _reactNative2.default.createElement(_reactNative.ListView, _extends({}, props, {
91 | ref: listViewRef,
92 | dataSource: ds
93 | }));
94 | }
95 | }]);
96 |
97 | return MeteorListView;
98 | }(_reactNative.Component);
99 |
100 | MeteorListView.propTypes = {
101 | elements: _reactNative.PropTypes.func.isRequired,
102 | renderRow: _reactNative.PropTypes.func.isRequired,
103 | listViewRef: _reactNative.PropTypes.oneOfType([_reactNative.PropTypes.func, _reactNative.PropTypes.string])
104 | };
105 | exports.default = MeteorListView;
--------------------------------------------------------------------------------
/dist/CollectionFS/FSCollectionImagesPreloader.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 |
7 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
8 |
9 | var _reactNative = require('react-native');
10 |
11 | var _reactNative2 = _interopRequireDefault(_reactNative);
12 |
13 | var _Data = require('../Data');
14 |
15 | var _Data2 = _interopRequireDefault(_Data);
16 |
17 | var _setProperties = require('./setProperties');
18 |
19 | var _setProperties2 = _interopRequireDefault(_setProperties);
20 |
21 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
22 |
23 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
24 |
25 | function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
26 |
27 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
28 |
29 | var FSCollectionImagesPreloader = function (_Component) {
30 | _inherits(FSCollectionImagesPreloader, _Component);
31 |
32 | function FSCollectionImagesPreloader(props) {
33 | _classCallCheck(this, FSCollectionImagesPreloader);
34 |
35 | var _this = _possibleConstructorReturn(this, Object.getPrototypeOf(FSCollectionImagesPreloader).call(this, props));
36 |
37 | _this.state = {
38 | items: []
39 | };
40 | return _this;
41 | }
42 |
43 | _createClass(FSCollectionImagesPreloader, [{
44 | key: 'componentWillMount',
45 | value: function componentWillMount() {
46 | var _this2 = this;
47 |
48 | var _props = this.props;
49 | var collection = _props.collection;
50 | var selector = _props.selector;
51 |
52 |
53 | this.update = function (results) {
54 | _this2.setState({
55 | items: results.map(function (elem) {
56 | return (0, _setProperties2.default)(collection, elem);
57 | })
58 | });
59 | };
60 |
61 | var collectionName = 'cfs.' + collection + '.filerecord';
62 |
63 | if (!_Data2.default.db[collectionName]) {
64 | _Data2.default.db.addCollection(collectionName);
65 | }
66 |
67 | this.items = _Data2.default.db.observe(function () {
68 | return _Data2.default.db[collectionName].find(selector);
69 | });
70 |
71 | this.items.subscribe(this.update);
72 | }
73 | }, {
74 | key: 'componentWillUnmount',
75 | value: function componentWillUnmount() {
76 | this.items.dispose();
77 | }
78 | }, {
79 | key: 'render',
80 | value: function render() {
81 | var items = this.state.items;
82 |
83 |
84 | return _reactNative2.default.createElement(
85 | _reactNative.View,
86 | { style: styles.hidden },
87 | items && items.map(function (item) {
88 | return _reactNative2.default.createElement(_reactNative.Image, { style: styles.hidden, key: item._id, source: { uri: item.url() } });
89 | })
90 | );
91 | }
92 | }]);
93 |
94 | return FSCollectionImagesPreloader;
95 | }(_reactNative.Component);
96 |
97 | FSCollectionImagesPreloader.propTypes = {
98 | collection: _reactNative.PropTypes.string.isRequired,
99 | selector: _reactNative.PropTypes.oneOfType([_reactNative.PropTypes.string, _reactNative.PropTypes.object])
100 | };
101 | FSCollectionImagesPreloader.defaultProps = {
102 | selector: {}
103 | };
104 | exports.default = FSCollectionImagesPreloader;
105 |
106 |
107 | var styles = _reactNative.StyleSheet.create({
108 | hidden: {
109 | width: 1,
110 | height: 1,
111 | position: 'absolute',
112 | top: -100000,
113 | left: -10000,
114 | opacity: 0
115 | }
116 | });
--------------------------------------------------------------------------------
/dist/components/ListView.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 |
7 | var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
8 |
9 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
10 |
11 | var _reactNative = require('react-native');
12 |
13 | var _reactNative2 = _interopRequireDefault(_reactNative);
14 |
15 | var _Data = require('../Data');
16 |
17 | var _Data2 = _interopRequireDefault(_Data);
18 |
19 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
20 |
21 | function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
22 |
23 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
24 |
25 | function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
26 |
27 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
28 |
29 | var MeteorListView = function (_Component) {
30 | _inherits(MeteorListView, _Component);
31 |
32 | function MeteorListView(props) {
33 | _classCallCheck(this, MeteorListView);
34 |
35 | var _this = _possibleConstructorReturn(this, Object.getPrototypeOf(MeteorListView).call(this, props));
36 |
37 | _this.state = {
38 | ds: new _reactNative.ListView.DataSource({
39 | rowHasChanged: function rowHasChanged(row1, row2) {
40 | return row1 !== row2;
41 | }
42 | })
43 | };
44 | return _this;
45 | }
46 |
47 | _createClass(MeteorListView, [{
48 | key: 'componentWillReceiveProps',
49 | value: function componentWillReceiveProps(props) {
50 | var collection = props.collection;
51 | var selector = props.selector;
52 | var options = props.options;
53 |
54 |
55 | this.update(_Data2.default.db[collection].find(selector, options));
56 | }
57 | }, {
58 | key: 'componentWillMount',
59 | value: function componentWillMount() {
60 | var _this2 = this;
61 |
62 | var _props = this.props;
63 | var collection = _props.collection;
64 | var selector = _props.selector;
65 | var options = _props.options;
66 |
67 |
68 | this.update = function (results) {
69 | _this2.setState({
70 | ds: _this2.state.ds.cloneWithRows(results)
71 | });
72 | };
73 |
74 | if (!_Data2.default.db[collection]) {
75 | _Data2.default.db.addCollection(collection);
76 | }
77 |
78 | this.items = _Data2.default.db.observe(function () {
79 | return _Data2.default.db[collection].find(selector, options);
80 | });
81 |
82 | this.items.subscribe(this.update);
83 | }
84 | }, {
85 | key: 'componentWillUnmount',
86 | value: function componentWillUnmount() {
87 | this.items.dispose();
88 | }
89 | }, {
90 | key: 'render',
91 | value: function render() {
92 | var ds = this.state.ds;
93 | var _props2 = this.props;
94 | var listViewRef = _props2.listViewRef;
95 |
96 | var props = _objectWithoutProperties(_props2, ['listViewRef']);
97 |
98 | return _reactNative2.default.createElement(_reactNative.ListView, _extends({}, props, {
99 | ref: listViewRef,
100 | dataSource: ds
101 | }));
102 | }
103 | }]);
104 |
105 | return MeteorListView;
106 | }(_reactNative.Component);
107 |
108 | MeteorListView.propTypes = {
109 | collection: _reactNative.PropTypes.string.isRequired,
110 | selector: _reactNative.PropTypes.oneOfType([_reactNative.PropTypes.string, _reactNative.PropTypes.object]),
111 | options: _reactNative.PropTypes.oneOfType([_reactNative.PropTypes.string, _reactNative.PropTypes.object]),
112 | renderRow: _reactNative.PropTypes.func.isRequired,
113 | listViewRef: _reactNative.PropTypes.oneOfType([_reactNative.PropTypes.func, _reactNative.PropTypes.string])
114 | };
115 | MeteorListView.defaultProps = {
116 | selector: {}
117 | };
118 | exports.default = MeteorListView;
--------------------------------------------------------------------------------
/dist/user/User.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var _reactNative = require('react-native');
4 |
5 | var _Data = require('../Data');
6 |
7 | var _Data2 = _interopRequireDefault(_Data);
8 |
9 | var _utils = require('../../lib/utils');
10 |
11 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
12 |
13 | function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { return step("next", value); }, function (err) { return step("throw", err); }); } } return step("next"); }); }; }
14 |
15 | var TOKEN_KEY = 'reactnativemeteor_usertoken';
16 |
17 | module.exports = {
18 | user: function user() {
19 | if (!this._userIdSaved) return null;
20 |
21 | return this.collection('users').findOne(this._userIdSaved);
22 | },
23 | userId: function userId() {
24 | if (!this._userIdSaved) return null;
25 |
26 | var user = this.collection('users').findOne(this._userIdSaved);
27 | return user && user._id;
28 | },
29 |
30 | _isLoggingIn: true,
31 | loggingIn: function loggingIn() {
32 | return this._isLoggingIn;
33 | },
34 | logout: function logout(callback) {
35 | var _this = this;
36 |
37 | this.call("logout", function (err) {
38 | _this.handleLogout();
39 | _this.connect();
40 |
41 | typeof callback == 'function' && callback(err);
42 | });
43 | },
44 | handleLogout: function handleLogout() {
45 | _reactNative.AsyncStorage.removeItem(TOKEN_KEY);
46 | _Data2.default._tokenIdSaved = null;
47 | this._userIdSaved = null;
48 | },
49 | loginWithPassword: function loginWithPassword(selector, password, callback) {
50 | var _this2 = this;
51 |
52 | if (typeof selector === 'string') {
53 | if (selector.indexOf('@') === -1) selector = { username: selector };else selector = { email: selector };
54 | }
55 |
56 | this._startLoggingIn();
57 | this.call("login", {
58 | user: selector,
59 | password: (0, _utils.hashPassword)(password)
60 | }, function (err, result) {
61 | _this2._endLoggingIn();
62 |
63 | _this2._handleLoginCallback(err, result);
64 |
65 | typeof callback == 'function' && callback(err);
66 | });
67 | },
68 | logoutOtherClients: function logoutOtherClients() {
69 | var _this3 = this;
70 |
71 | var callback = arguments.length <= 0 || arguments[0] === undefined ? function () {} : arguments[0];
72 |
73 | this.call('getNewToken', function (err, res) {
74 | if (err) return callback(err);
75 |
76 | _this3._handleLoginCallback(err, res);
77 |
78 | _this3.call('removeOtherTokens', function (err) {
79 | callback(err);
80 | });
81 | });
82 | },
83 | _startLoggingIn: function _startLoggingIn() {
84 | this._isLoggingIn = true;
85 | _Data2.default.notify('loggingIn');
86 | },
87 | _endLoggingIn: function _endLoggingIn() {
88 | this._isLoggingIn = false;
89 | _Data2.default.notify('loggingIn');
90 | },
91 | _handleLoginCallback: function _handleLoginCallback(err, result) {
92 | if (!err) {
93 | //save user id and token
94 | _reactNative.AsyncStorage.setItem(TOKEN_KEY, result.token);
95 | _Data2.default._tokenIdSaved = result.token;
96 | this._userIdSaved = result.id;
97 | _Data2.default.notify('onLogin');
98 | } else {
99 | _Data2.default.notify('onLoginFailure');
100 | this.handleLogout();
101 | }
102 | _Data2.default.notify('change');
103 | },
104 | _loadInitialUser: function _loadInitialUser() {
105 | var _this4 = this;
106 |
107 | return _asyncToGenerator(regeneratorRuntime.mark(function _callee() {
108 | var value;
109 | return regeneratorRuntime.wrap(function _callee$(_context) {
110 | while (1) {
111 | switch (_context.prev = _context.next) {
112 | case 0:
113 | value = null;
114 | _context.prev = 1;
115 | _context.next = 4;
116 | return _reactNative.AsyncStorage.getItem(TOKEN_KEY);
117 |
118 | case 4:
119 | value = _context.sent;
120 | _context.next = 10;
121 | break;
122 |
123 | case 7:
124 | _context.prev = 7;
125 | _context.t0 = _context['catch'](1);
126 |
127 | console.warn('AsyncStorage error: ' + _context.t0.message);
128 |
129 | case 10:
130 | _context.prev = 10;
131 |
132 | _Data2.default._tokenIdSaved = value;
133 | if (value !== null) {
134 | _this4._startLoggingIn();
135 | _this4.call('login', { resume: value }, function (err, result) {
136 | _this4._endLoggingIn();
137 | _this4._handleLoginCallback(err, result);
138 | });
139 | } else {
140 | _this4._endLoggingIn();
141 | }
142 | return _context.finish(10);
143 |
144 | case 14:
145 | case 'end':
146 | return _context.stop();
147 | }
148 | }
149 | }, _callee, _this4, [[1, 7, 10, 14]]);
150 | }))();
151 | }
152 | };
--------------------------------------------------------------------------------
/dist/lib/socket.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 |
7 | var _classCallCheck2 = require("babel-runtime/helpers/classCallCheck");
8 |
9 | var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
10 |
11 | var _createClass2 = require("babel-runtime/helpers/createClass");
12 |
13 | var _createClass3 = _interopRequireDefault(_createClass2);
14 |
15 | var _possibleConstructorReturn2 = require("babel-runtime/helpers/possibleConstructorReturn");
16 |
17 | var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
18 |
19 | var _inherits2 = require("babel-runtime/helpers/inherits");
20 |
21 | var _inherits3 = _interopRequireDefault(_inherits2);
22 |
23 | var _wolfy87Eventemitter = require("wolfy87-eventemitter");
24 |
25 | var _wolfy87Eventemitter2 = _interopRequireDefault(_wolfy87Eventemitter);
26 |
27 | var _ejson = require("ejson");
28 |
29 | var _ejson2 = _interopRequireDefault(_ejson);
30 |
31 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
32 |
33 | var Socket = function (_EventEmitter) {
34 | (0, _inherits3.default)(Socket, _EventEmitter);
35 |
36 | function Socket(SocketConstructor, endpoint) {
37 | (0, _classCallCheck3.default)(this, Socket);
38 |
39 | var _this = (0, _possibleConstructorReturn3.default)(this, Object.getPrototypeOf(Socket).call(this));
40 |
41 | _this.SocketConstructor = SocketConstructor;
42 | _this.endpoint = endpoint;
43 | _this.rawSocket = null;
44 | return _this;
45 | }
46 |
47 | (0, _createClass3.default)(Socket, [{
48 | key: "send",
49 | value: function send(object) {
50 | var message = _ejson2.default.stringify(object);
51 | this.rawSocket.send(message);
52 | // Emit a copy of the object, as the listener might mutate it.
53 | this.emit("message:out", _ejson2.default.parse(message));
54 | }
55 | }, {
56 | key: "open",
57 | value: function open() {
58 | var _this2 = this;
59 |
60 | /*
61 | * Makes `open` a no-op if there's already a `rawSocket`. This avoids
62 | * memory / socket leaks if `open` is called twice (e.g. by a user
63 | * calling `ddp.connect` twice) without properly disposing of the
64 | * socket connection. `rawSocket` gets automatically set to `null` only
65 | * when it goes into a closed or error state. This way `rawSocket` is
66 | * disposed of correctly: the socket connection is closed, and the
67 | * object can be garbage collected.
68 | */
69 | if (this.rawSocket) {
70 | return;
71 | }
72 | this.rawSocket = new this.SocketConstructor(this.endpoint);
73 |
74 | /*
75 | * Calls to `onopen` and `onclose` directly trigger the `open` and
76 | * `close` events on the `Socket` instance.
77 | */
78 | this.rawSocket.onopen = function () {
79 | return _this2.emit("open");
80 | };
81 | this.rawSocket.onclose = function () {
82 | _this2.rawSocket = null;
83 | _this2.emit("close");
84 | };
85 | /*
86 | * Calls to `onerror` trigger the `close` event on the `Socket`
87 | * instance, and cause the `rawSocket` object to be disposed of.
88 | * Since it's not clear what conditions could cause the error and if
89 | * it's possible to recover from it, we prefer to always close the
90 | * connection (if it isn't already) and dispose of the socket object.
91 | */
92 | this.rawSocket.onerror = function () {
93 | // It's not clear what the socket lifecycle is when errors occurr.
94 | // Hence, to avoid the `close` event to be emitted twice, before
95 | // manually closing the socket we de-register the `onclose`
96 | // callback.
97 | delete _this2.rawSocket.onclose;
98 | // Safe to perform even if the socket is already closed
99 | _this2.rawSocket.close();
100 | _this2.rawSocket = null;
101 | _this2.emit("close");
102 | };
103 | /*
104 | * Calls to `onmessage` trigger a `message:in` event on the `Socket`
105 | * instance only once the message (first parameter to `onmessage`) has
106 | * been successfully parsed into a javascript object.
107 | */
108 | this.rawSocket.onmessage = function (message) {
109 | var object;
110 | try {
111 | object = _ejson2.default.parse(message.data);
112 | } catch (ignore) {
113 | // Simply ignore the malformed message and return
114 | return;
115 | }
116 | // Outside the try-catch block as it must only catch JSON parsing
117 | // errors, not errors that may occur inside a "message:in" event
118 | // handler
119 | _this2.emit("message:in", object);
120 | };
121 | }
122 | }, {
123 | key: "close",
124 | value: function close() {
125 | /*
126 | * Avoid throwing an error if `rawSocket === null`
127 | */
128 | if (this.rawSocket) {
129 | this.rawSocket.close();
130 | }
131 | }
132 | }]);
133 | return Socket;
134 | }(_wolfy87Eventemitter2.default);
135 |
136 | exports.default = Socket;
--------------------------------------------------------------------------------
/dist/src/user/User.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var _regenerator = require('babel-runtime/regenerator');
4 |
5 | var _regenerator2 = _interopRequireDefault(_regenerator);
6 |
7 | var _asyncToGenerator2 = require('babel-runtime/helpers/asyncToGenerator');
8 |
9 | var _asyncToGenerator3 = _interopRequireDefault(_asyncToGenerator2);
10 |
11 | var _electronJsonStorage = require('electron-json-storage');
12 |
13 | var _electronJsonStorage2 = _interopRequireDefault(_electronJsonStorage);
14 |
15 | var _Data = require('../Data');
16 |
17 | var _Data2 = _interopRequireDefault(_Data);
18 |
19 | var _utils = require('../../lib/utils');
20 |
21 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
22 |
23 | var TOKEN_KEY = 'reactnativemeteor_usertoken'; //import { AsyncStorage } from 'react-native';
24 |
25 |
26 | module.exports = {
27 | user: function user() {
28 | if (!this._userIdSaved) return null;
29 |
30 | return this.collection('users').findOne(this._userIdSaved);
31 | },
32 | userId: function userId() {
33 | if (!this._userIdSaved) return null;
34 |
35 | var user = this.collection('users').findOne(this._userIdSaved);
36 | return user && user._id;
37 | },
38 |
39 | _isLoggingIn: true,
40 | loggingIn: function loggingIn() {
41 | return this._isLoggingIn;
42 | },
43 | logout: function logout(callback) {
44 | var _this = this;
45 |
46 | this.call("logout", function (err) {
47 | _this.handleLogout();
48 | _this.connect();
49 |
50 | typeof callback == 'function' && callback(err);
51 | });
52 | },
53 | handleLogout: function handleLogout() {
54 | _electronJsonStorage2.default.remove(TOKEN_KEY);
55 | _Data2.default._tokenIdSaved = null;
56 | this._userIdSaved = null;
57 | },
58 | loginWithPassword: function loginWithPassword(selector, password, callback) {
59 | var _this2 = this;
60 |
61 | if (typeof selector === 'string') {
62 | if (selector.indexOf('@') === -1) selector = { username: selector };else selector = { email: selector };
63 | }
64 |
65 | this._startLoggingIn();
66 | this.call("login", {
67 | user: selector,
68 | password: (0, _utils.hashPassword)(password)
69 | }, function (err, result) {
70 | _this2._endLoggingIn();
71 |
72 | _this2._handleLoginCallback(err, result);
73 |
74 | typeof callback == 'function' && callback(err);
75 | });
76 | },
77 | logoutOtherClients: function logoutOtherClients() {
78 | var _this3 = this;
79 |
80 | var callback = arguments.length <= 0 || arguments[0] === undefined ? function () {} : arguments[0];
81 |
82 | this.call('getNewToken', function (err, res) {
83 | if (err) return callback(err);
84 |
85 | _this3._handleLoginCallback(err, res);
86 |
87 | _this3.call('removeOtherTokens', function (err) {
88 | callback(err);
89 | });
90 | });
91 | },
92 | _startLoggingIn: function _startLoggingIn() {
93 | this._isLoggingIn = true;
94 | _Data2.default.notify('loggingIn');
95 | },
96 | _endLoggingIn: function _endLoggingIn() {
97 | this._isLoggingIn = false;
98 | _Data2.default.notify('loggingIn');
99 | },
100 | _handleLoginCallback: function _handleLoginCallback(err, result) {
101 | if (!err) {
102 | //save user id and token
103 | _electronJsonStorage2.default.set(TOKEN_KEY, { token: result.token });
104 | _Data2.default._tokenIdSaved = result.token;
105 | this._userIdSaved = result.id;
106 | _Data2.default.notify('onLogin');
107 | } else {
108 | _Data2.default.notify('onLoginFailure');
109 | this.handleLogout();
110 | }
111 | _Data2.default.notify('change');
112 | },
113 | _loadInitialUser: function _loadInitialUser() {
114 | var _this4 = this;
115 |
116 | return (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee() {
117 | var value, getStorage;
118 | return _regenerator2.default.wrap(function _callee$(_context) {
119 | while (1) {
120 | switch (_context.prev = _context.next) {
121 | case 0:
122 | value = null;
123 | _context.prev = 1;
124 |
125 | getStorage = function getStorage() {
126 | return new Promise(function (resolve, reject) {
127 | _electronJsonStorage2.default.get(TOKEN_KEY, function (err, res) {
128 | resolve(res);
129 | });
130 | });
131 | };
132 |
133 | _context.next = 5;
134 | return getStorage();
135 |
136 | case 5:
137 | value = _context.sent;
138 |
139 | value = value.token;
140 | _context.next = 12;
141 | break;
142 |
143 | case 9:
144 | _context.prev = 9;
145 | _context.t0 = _context['catch'](1);
146 |
147 | console.warn('json-storage error: ' + _context.t0.message);
148 |
149 | case 12:
150 | _context.prev = 12;
151 |
152 | _Data2.default._tokenIdSaved = value;
153 | if (value !== null) {
154 | _this4._startLoggingIn();
155 | _this4.call('login', { resume: value }, function (err, result) {
156 | _this4._endLoggingIn();
157 | _this4._handleLoginCallback(err, result);
158 | });
159 | } else {
160 | _this4._endLoggingIn();
161 | }
162 | return _context.finish(12);
163 |
164 | case 16:
165 | case 'end':
166 | return _context.stop();
167 | }
168 | }
169 | }, _callee, _this4, [[1, 9, 12, 16]]);
170 | }))();
171 | }
172 | };
--------------------------------------------------------------------------------
/dist/lib/ddp.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 |
7 | var _classCallCheck2 = require("babel-runtime/helpers/classCallCheck");
8 |
9 | var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
10 |
11 | var _possibleConstructorReturn2 = require("babel-runtime/helpers/possibleConstructorReturn");
12 |
13 | var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
14 |
15 | var _createClass2 = require("babel-runtime/helpers/createClass");
16 |
17 | var _createClass3 = _interopRequireDefault(_createClass2);
18 |
19 | var _inherits2 = require("babel-runtime/helpers/inherits");
20 |
21 | var _inherits3 = _interopRequireDefault(_inherits2);
22 |
23 | var _get3 = require("babel-runtime/helpers/get");
24 |
25 | var _get4 = _interopRequireDefault(_get3);
26 |
27 | var _wolfy87Eventemitter = require("wolfy87-eventemitter");
28 |
29 | var _wolfy87Eventemitter2 = _interopRequireDefault(_wolfy87Eventemitter);
30 |
31 | var _queue = require("./queue");
32 |
33 | var _queue2 = _interopRequireDefault(_queue);
34 |
35 | var _socket = require("./socket");
36 |
37 | var _socket2 = _interopRequireDefault(_socket);
38 |
39 | var _utils = require("./utils");
40 |
41 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
42 |
43 | /**
44 | * DDP.JS 2.1.0
45 | */
46 |
47 | var DDP_VERSION = "1";
48 | var PUBLIC_EVENTS = [
49 | // Subscription messages
50 | "ready", "nosub", "added", "changed", "removed",
51 | // Method messages
52 | "result", "updated",
53 | // Error messages
54 | "error"];
55 | var DEFAULT_RECONNECT_INTERVAL = 10000;
56 |
57 | var DDP = function (_EventEmitter) {
58 | (0, _inherits3.default)(DDP, _EventEmitter);
59 | (0, _createClass3.default)(DDP, [{
60 | key: "emit",
61 | value: function emit() {
62 | var _get2;
63 |
64 | setTimeout((_get2 = (0, _get4.default)(Object.getPrototypeOf(DDP.prototype), "emit", this)).bind.apply(_get2, [this].concat(Array.prototype.slice.call(arguments))), 0);
65 | }
66 | }]);
67 |
68 | function DDP(options) {
69 | (0, _classCallCheck3.default)(this, DDP);
70 |
71 | var _this = (0, _possibleConstructorReturn3.default)(this, Object.getPrototypeOf(DDP).call(this));
72 |
73 | _this.status = "disconnected";
74 |
75 | // Default `autoConnect` and `autoReconnect` to true
76 | _this.autoConnect = options.autoConnect !== false;
77 | _this.autoReconnect = options.autoReconnect !== false;
78 | _this.reconnectInterval = options.reconnectInterval || DEFAULT_RECONNECT_INTERVAL;
79 |
80 | _this.messageQueue = new _queue2.default(function (message) {
81 | if (_this.status === "connected") {
82 | _this.socket.send(message);
83 | return true;
84 | } else {
85 | return false;
86 | }
87 | });
88 |
89 | _this.socket = new _socket2.default(options.SocketConstructor, options.endpoint);
90 |
91 | _this.socket.on("open", function () {
92 | // When the socket opens, send the `connect` message
93 | // to establish the DDP connection
94 | _this.socket.send({
95 | msg: "connect",
96 | version: DDP_VERSION,
97 | support: [DDP_VERSION]
98 | });
99 | });
100 |
101 | _this.socket.on("close", function () {
102 | _this.status = "disconnected";
103 | _this.messageQueue.empty();
104 | _this.emit("disconnected");
105 | if (_this.autoReconnect) {
106 | // Schedule a reconnection
107 | setTimeout(_this.socket.open.bind(_this.socket), _this.reconnectInterval);
108 | }
109 | });
110 |
111 | _this.socket.on("message:in", function (message) {
112 | if (message.msg === "connected") {
113 | _this.status = "connected";
114 | _this.messageQueue.process();
115 | _this.emit("connected");
116 | } else if (message.msg === "ping") {
117 | // Reply with a `pong` message to prevent the server from
118 | // closing the connection
119 | _this.socket.send({ msg: "pong", id: message.id });
120 | } else if ((0, _utils.contains)(PUBLIC_EVENTS, message.msg)) {
121 | _this.emit(message.msg, message);
122 | }
123 | });
124 |
125 | if (_this.autoConnect) {
126 | _this.connect();
127 | }
128 |
129 | return _this;
130 | }
131 |
132 | (0, _createClass3.default)(DDP, [{
133 | key: "connect",
134 | value: function connect() {
135 | this.socket.open();
136 | }
137 | }, {
138 | key: "disconnect",
139 | value: function disconnect() {
140 | /*
141 | * If `disconnect` is called, the caller likely doesn't want the
142 | * the instance to try to auto-reconnect. Therefore we set the
143 | * `autoReconnect` flag to false.
144 | */
145 | this.autoReconnect = false;
146 | this.socket.close();
147 | }
148 | }, {
149 | key: "method",
150 | value: function method(name, params) {
151 | var id = (0, _utils.uniqueId)();
152 | this.messageQueue.push({
153 | msg: "method",
154 | id: id,
155 | method: name,
156 | params: params
157 | });
158 | return id;
159 | }
160 | }, {
161 | key: "sub",
162 | value: function sub(name, params) {
163 | var id = (0, _utils.uniqueId)();
164 | this.messageQueue.push({
165 | msg: "sub",
166 | id: id,
167 | name: name,
168 | params: params
169 | });
170 | return id;
171 | }
172 | }, {
173 | key: "unsub",
174 | value: function unsub(id) {
175 | this.messageQueue.push({
176 | msg: "unsub",
177 | id: id
178 | });
179 | return id;
180 | }
181 | }]);
182 | return DDP;
183 | }(_wolfy87Eventemitter2.default);
184 |
185 | exports.default = DDP;
--------------------------------------------------------------------------------
/src/components/Mixin.js:
--------------------------------------------------------------------------------
1 | import Trackr from 'trackr';
2 | import EJSON from 'ejson';
3 | import Data from '../Data';
4 |
5 | export default {
6 | componentWillMount() {
7 |
8 | Data.waitDdpReady(()=>{
9 | if(this.getMeteorData) {
10 | this.data = {};
11 | this._meteorDataManager = new MeteorDataManager(this);
12 | const newData = this._meteorDataManager.calculateData();
13 | this._meteorDataManager.updateData(newData);
14 | }
15 |
16 | if(this.startMeteorSubscriptions) {
17 | console.warn('startMeteorSubscriptions is deprecated and will be removed soon. Please create your subscriptions in getMeteorData.');
18 | this._meteorSubscriptionsManager = new MeteorSubscriptionsManager(this);
19 | this._meteorSubscriptionsManager.getMeteorSubscriptions();
20 | }
21 | });
22 |
23 |
24 | },
25 | componentWillUpdate(nextProps, nextState) {
26 |
27 | if(this.startMeteorSubscriptions) {
28 | if(!EJSON.equals(this.state, nextState) || !EJSON.equals(this.props, nextProps)) {
29 | this._meteorSubscriptionsManager._meteorDataChangedCallback()
30 | }
31 | }
32 |
33 | if(this.getMeteorData) {
34 | const saveProps = this.props;
35 | const saveState = this.state;
36 | let newData;
37 | try {
38 | // Temporarily assign this.state and this.props,
39 | // so that they are seen by getMeteorData!
40 | // This is a simulation of how the proposed Observe API
41 | // for React will work, which calls observe() after
42 | // componentWillUpdate and after props and state are
43 | // updated, but before render() is called.
44 | // See https://github.com/facebook/react/issues/3398.
45 | this.props = nextProps;
46 | this.state = nextState;
47 | newData = this._meteorDataManager.calculateData();
48 | } finally {
49 | this.props = saveProps;
50 | this.state = saveState;
51 | }
52 |
53 | this._meteorDataManager.updateData(newData);
54 | }
55 |
56 | },
57 | componentWillUnmount() {
58 | if(this._meteorDataManager) {
59 | this._meteorDataManager.dispose();
60 | }
61 |
62 | if(this._meteorSubscriptionsManager) {
63 | this._meteorSubscriptionsManager.dispose();
64 | }
65 |
66 | }
67 | };
68 |
69 |
70 |
71 |
72 |
73 | class MeteorSubscriptionsManager {
74 | constructor(component) {
75 | this.component = component;
76 | this.computation = null;
77 |
78 | this._meteorSubscriptionsDep = new Trackr.Dependency();
79 |
80 | this._meteorDataChangedCallback = ()=>{this._meteorSubscriptionsDep.changed()};
81 |
82 | Data.onChange(this._meteorDataChangedCallback);
83 | }
84 | dispose() {
85 | if (this.computation) {
86 | this.computation.stop();
87 | this.computation = null;
88 | }
89 |
90 | Data.offChange(this._meteorDataChangedCallback);
91 | }
92 | stateOrPropsChanged() {
93 |
94 | }
95 | getMeteorSubscriptions() {
96 | this.computation = Trackr.nonreactive(() => {
97 | return Trackr.autorun((c) => {
98 | this._meteorSubscriptionsDep.depend();
99 |
100 | this.component.startMeteorSubscriptions();
101 |
102 | });
103 | });
104 | }
105 |
106 | }
107 |
108 |
109 | // A class to keep the state and utility methods needed to manage
110 | // the Meteor data for a component.
111 | class MeteorDataManager {
112 | constructor(component) {
113 | this.component = component;
114 | this.computation = null;
115 | this.oldData = null;
116 | this._meteorDataDep = new Trackr.Dependency();
117 |
118 | this._meteorDataChangedCallback = ()=>{this._meteorDataDep.changed()};
119 |
120 | Data.onChange(this._meteorDataChangedCallback);
121 | }
122 |
123 | dispose() {
124 | if (this.computation) {
125 | this.computation.stop();
126 | this.computation = null;
127 | }
128 |
129 | Data.offChange(this._meteorDataChangedCallback);
130 | }
131 |
132 | calculateData() {
133 | const component = this.component;
134 |
135 | if (!component.getMeteorData) {
136 | return null;
137 | }
138 |
139 | if (this.computation) {
140 | this.computation.stop();
141 | this.computation = null;
142 | }
143 |
144 | let data;
145 | // Use Tracker.nonreactive in case we are inside a Tracker Computation.
146 | // This can happen if someone calls `ReactDOM.render` inside a Computation.
147 | // In that case, we want to opt out of the normal behavior of nested
148 | // Computations, where if the outer one is invalidated or stopped,
149 | // it stops the inner one.
150 |
151 | this.computation = Trackr.nonreactive(() => {
152 | return Trackr.autorun((c) => {
153 | this._meteorDataDep.depend();
154 | if (c.firstRun) {
155 | const savedSetState = component.setState;
156 | try {
157 | component.setState = () => {
158 | throw new Error(
159 | "Can't call `setState` inside `getMeteorData` as this could cause an endless" +
160 | " loop. To respond to Meteor data changing, consider making this component" +
161 | " a \"wrapper component\" that only fetches data and passes it in as props to" +
162 | " a child component. Then you can use `componentWillReceiveProps` in that" +
163 | " child component.");
164 | };
165 |
166 | data = component.getMeteorData();
167 | } finally {
168 | component.setState = savedSetState;
169 | }
170 |
171 |
172 | } else {
173 | // Stop this computation instead of using the re-run.
174 | // We use a brand-new autorun for each call to getMeteorData
175 | // to capture dependencies on any reactive data sources that
176 | // are accessed. The reason we can't use a single autorun
177 | // for the lifetime of the component is that Tracker only
178 | // re-runs autoruns at flush time, while we need to be able to
179 | // re-call getMeteorData synchronously whenever we want, e.g.
180 | // from componentWillUpdate.
181 | c.stop();
182 | // Calling forceUpdate() triggers componentWillUpdate which
183 | // recalculates getMeteorData() and re-renders the component.
184 | component.forceUpdate();
185 | }
186 | });
187 | });
188 |
189 | return data;
190 | }
191 |
192 | updateData(newData) {
193 | const component = this.component;
194 | const oldData = this.oldData;
195 |
196 | if (! (newData && (typeof newData) === 'object')) {
197 | throw new Error("Expected object returned from getMeteorData");
198 | }
199 | // update componentData in place based on newData
200 | for (let key in newData) {
201 | component.data[key] = newData[key];
202 | }
203 | // if there is oldData (which is every time this method is called
204 | // except the first), delete keys in newData that aren't in
205 | // oldData. don't interfere with other keys, in case we are
206 | // co-existing with something else that writes to a component's
207 | // this.data.
208 | if (oldData) {
209 | for (let key in oldData) {
210 | if (!(key in newData)) {
211 | delete component.data[key];
212 | }
213 | }
214 | }
215 | this.oldData = newData;
216 | }
217 | }
218 |
219 |
--------------------------------------------------------------------------------
/src/Meteor.js:
--------------------------------------------------------------------------------
1 |
2 | //import { NetInfo } from 'react-native';
3 |
4 | import reactMixin from 'react-mixin';
5 | import Trackr from 'trackr';
6 | import EJSON from 'ejson';
7 | import DDP from '../lib/ddp.js';
8 | import Random from '../lib/Random';
9 |
10 | import Data from './Data';
11 | import collection from './Collection';
12 | import call from './Call';
13 |
14 | import Mixin from './components/Mixin';
15 | import createContainer from './components/createContainer';
16 |
17 | import FSCollection from './CollectionFS/FSCollection';
18 | import FSCollectionImagesPreloader from './CollectionFS/FSCollectionImagesPreloader';
19 |
20 | import User from './user/User';
21 | import Accounts from './user/Accounts';
22 |
23 |
24 | module.exports = {
25 | Accounts: Accounts,
26 | FSCollectionImagesPreloader: FSCollectionImagesPreloader,
27 | collection: collection,
28 | FSCollection: FSCollection,
29 | createContainer: createContainer,
30 | getData() {
31 | return Data;
32 | },
33 | connectMeteor(reactClass) {
34 | return reactMixin.onClass(reactClass, Mixin);
35 | },
36 | ...User,
37 | status() {
38 | return {
39 | connected: Data.ddp ? Data.ddp.status=="connected" : false,
40 | status: Data.ddp ? Data.ddp.status : "disconnected"
41 | //retryCount: 0
42 | //retryTime:
43 | //reason:
44 | }
45 | },
46 | call: call,
47 | disconnect() {
48 | if(Data.ddp) {
49 | Data.ddp.disconnect();
50 | }
51 | },
52 | _subscriptionsRestart() {
53 |
54 | for(var i in Data.subscriptions) {
55 | const sub = Data.subscriptions[i];
56 | Data.ddp.unsub(sub.subIdRemember);
57 | sub.subIdRemember = Data.ddp.sub(sub.name, sub.params);
58 | }
59 |
60 | },
61 | waitDdpConnected(cb) {
62 |
63 | if(Data.ddp && Data.ddp.status == 'connected') {
64 | cb();
65 | } else if(Data.ddp) {
66 | Data.ddp.once('connected', cb);
67 | } else {
68 | setTimeout(()=>{ this.waitDdpConnected(cb) }, 10);
69 | }
70 |
71 | },
72 | reconnect() {
73 | Data.ddp && Data.ddp.connect();
74 | },
75 | connect(endpoint, options) {
76 | if(!endpoint) endpoint = Data._endpoint;
77 | if(!options) options = Data._options;
78 |
79 | Data._endpoint = endpoint;
80 | Data._options = options;
81 |
82 |
83 | this.ddp = Data.ddp = new DDP({
84 | endpoint: endpoint,
85 | SocketConstructor: WebSocket,
86 | ...options
87 | });
88 |
89 | this.subscribe('_roles');
90 | //TODO
91 | /*
92 | NetInfo.isConnected.addEventListener('change', isConnected=>{
93 | if(isConnected) {
94 | Data.ddp.connect();
95 | }
96 | });
97 | */
98 |
99 |
100 | Data.ddp.on("connected", ()=>{
101 | console.info("Connected to DDP server.");
102 | this._loadInitialUser();
103 |
104 | this._subscriptionsRestart();
105 | });
106 |
107 | let lastDisconnect = null;
108 | Data.ddp.on("disconnected", ()=>{
109 | console.info("Disconnected from DDP server.");
110 |
111 | if(!lastDisconnect || new Date() - lastDisconnect > 3000) {
112 | Data.ddp.connect();
113 | }
114 |
115 | lastDisconnect = new Date();
116 |
117 | });
118 |
119 | Data.ddp.on("added", message => {
120 | if(!Data.db[message.collection]) {
121 | Data.db.addCollection(message.collection)
122 | }
123 | Data.db[message.collection].upsert({_id: message.id, ...message.fields});
124 | });
125 |
126 | Data.ddp.on("ready", message => {
127 |
128 | for(var i in Data.subscriptions) {
129 | const sub = Data.subscriptions[i];
130 | sub.ready = true;
131 | sub.readyDeps.changed();
132 | sub.readyCallback && sub.readyCallback();
133 | }
134 |
135 | });
136 |
137 | Data.ddp.on("changed", message => {
138 | Data.db[message.collection].upsert({_id: message.id, ...message.fields});
139 | });
140 |
141 | Data.ddp.on("removed", message => {
142 | Data.db[message.collection].del(message.id);
143 | });
144 | Data.ddp.on("result", message => {
145 | const call = Data.calls.find(call=>call.id==message.id);
146 | if(typeof call.callback == 'function') call.callback(message.error, message.result);
147 | Data.calls.splice(Data.calls.findIndex(call=>call.id==message.id), 1);
148 | });
149 |
150 | Data.ddp.on("nosub", message => {
151 | for(var i in Data.subscriptions) {
152 | const sub = Data.subscriptions[i];
153 | if(sub.subIdRemember == message.id) {
154 | console.warn("No subscription existing for", sub.name);
155 | }
156 | }
157 | });
158 |
159 | },
160 | subscribe(name) {
161 | var params = Array.prototype.slice.call(arguments, 1);
162 | var callbacks = {};
163 | if (params.length) {
164 | var lastParam = params[params.length - 1];
165 | if (typeof lastParam == 'function') {
166 | callbacks.onReady = params.pop();
167 | } else if (lastParam && (typeof lastParam.onReady == 'function' || typeof lastParam.onError == 'function' || typeof lastParam.onStop == 'function')) {
168 | callbacks = params.pop();
169 | }
170 | }
171 |
172 | // Is there an existing sub with the same name and param, run in an
173 | // invalidated Computation? This will happen if we are rerunning an
174 | // existing computation.
175 | //
176 | // For example, consider a rerun of:
177 | //
178 | // Tracker.autorun(function () {
179 | // Meteor.subscribe("foo", Session.get("foo"));
180 | // Meteor.subscribe("bar", Session.get("bar"));
181 | // });
182 | //
183 | // If "foo" has changed but "bar" has not, we will match the "bar"
184 | // subcribe to an existing inactive subscription in order to not
185 | // unsub and resub the subscription unnecessarily.
186 | //
187 | // We only look for one such sub; if there are N apparently-identical subs
188 | // being invalidated, we will require N matching subscribe calls to keep
189 | // them all active.
190 |
191 |
192 |
193 | let existing = false;
194 | for(var i in Data.subscriptions) {
195 | const sub = Data.subscriptions[i];
196 | if(sub.inactive && sub.name === name && EJSON.equals(sub.params, params)) existing = sub;
197 | }
198 |
199 | let id;
200 | if (existing) {
201 | id = existing.id;
202 | existing.inactive = false;
203 |
204 | if (callbacks.onReady) {
205 | // If the sub is not already ready, replace any ready callback with the
206 | // one provided now. (It's not really clear what users would expect for
207 | // an onReady callback inside an autorun; the semantics we provide is
208 | // that at the time the sub first becomes ready, we call the last
209 | // onReady callback provided, if any.)
210 | if (!existing.ready)
211 | existing.readyCallback = callbacks.onReady;
212 | }
213 | if (callbacks.onStop) {
214 | existing.stopCallback = callbacks.onStop;
215 | }
216 |
217 | } else {
218 |
219 | // New sub! Generate an id, save it locally, and send message.
220 |
221 | id = Random.id();
222 | const subIdRemember = Data.ddp.sub(name, params);
223 |
224 | Data.subscriptions[id] = {
225 | id: id,
226 | subIdRemember: subIdRemember,
227 | name: name,
228 | params: EJSON.clone(params),
229 | inactive: false,
230 | ready: false,
231 | readyDeps: new Trackr.Dependency,
232 | readyCallback: callbacks.onReady,
233 | stopCallback: callbacks.onStop,
234 | stop: function() {
235 | Data.ddp.unsub(this.subIdRemember);
236 | delete Data.subscriptions[this.id];
237 | this.ready && this.readyDeps.changed();
238 |
239 | if (callbacks.onStop) {
240 | callbacks.onStop();
241 | }
242 | }
243 | };
244 |
245 | }
246 |
247 |
248 | // return a handle to the application.
249 | var handle = {
250 | stop: function () {
251 | if(Data.subscriptions[id])
252 | Data.subscriptions[id].stop();
253 | },
254 | ready: function () {
255 | if (!Data.subscriptions[id]) return false;
256 |
257 | var record = Data.subscriptions[id];
258 | record.readyDeps.depend();
259 | return record.ready;
260 | },
261 | subscriptionId: id
262 | };
263 |
264 | if (Trackr.active) {
265 | // We're in a reactive computation, so we'd like to unsubscribe when the
266 | // computation is invalidated... but not if the rerun just re-subscribes
267 | // to the same subscription! When a rerun happens, we use onInvalidate
268 | // as a change to mark the subscription "inactive" so that it can
269 | // be reused from the rerun. If it isn't reused, it's killed from
270 | // an afterFlush.
271 | Trackr.onInvalidate(function (c) {
272 | if(Data.subscriptions[id]) {
273 | Data.subscriptions[id].inactive = true;
274 | }
275 |
276 | Trackr.afterFlush(function () {
277 | if (Data.subscriptions[id] && Data.subscriptions[id].inactive) {
278 | handle.stop();
279 | }
280 | });
281 | });
282 | }
283 |
284 | return handle;
285 |
286 | }
287 | }
288 |
289 |
290 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # electron-meteor [](https://www.npmjs.org/package/electron-meteor) [](http://badge.fury.io/js/electron-meteor) [](https://david-dm.org/inProgress-team/electron-meteor)
2 |
3 | Meteor-like methods for React Native.
4 |
5 | ## What is it for ?
6 |
7 | The purpose of this library is :
8 | * to set up and maintain a ddp connection with a ddp server, freeing the developer from having to do it on their own.
9 | * be fully compatible with react-native and help react-native developers.
10 | * **to match with [Meteor documentation](http://docs.meteor.com/) used with React.**
11 |
12 | ## Install
13 |
14 | npm i --save electron-meteor@latest
15 |
16 | [!! See detailed installation guide](https://github.com/inProgress-team/electron-meteor/blob/master/docs/Install.md)
17 |
18 | ## Example usage
19 |
20 | ```javascript
21 |
22 | import { View, Text, Component } from 'react-native';
23 | import Meteor, { createContainer } from 'electron-meteor';
24 |
25 | Meteor.connect('http://192.168.X.X:3000/websocket');//do this only once
26 |
27 | class App extends Component {
28 | renderRow(todo) {
29 | return (
30 | {todo.title}
31 | );
32 | }
33 | render() {
34 | const { settings, todosReady } = this.data;
35 |
36 |
37 | {settings.title}
38 | {!todosReady && Not ready}
39 |
40 |
46 |
47 |
48 | }
49 | }
50 |
51 | export default createContainer(params=>{
52 | const handle = Meteor.subscribe('todos');
53 | Meteor.subscribe('settings');
54 |
55 | return {
56 | todosReady: handle.ready(),
57 | settings: Meteor.collection('settings').findOne()
58 | };
59 | })
60 | ```
61 |
62 | # createContainer
63 |
64 | [Since Meteor 1.3, createContainer is the recommended way to go to populate your React Classes](http://guide.meteor.com/v1.3/react.html#using-createContainer). Very similar to getMeteorData but your separate container components from presentational components.
65 |
66 | ## Example
67 |
68 | ```javascript
69 | import Meteor, { createContainer } from 'electron-meteor';
70 |
71 |
72 | class Orders extends Component {
73 | render() {
74 | const { pendingOrders } = this.props;
75 |
76 | //...
77 | );
78 | }
79 | }
80 |
81 | export default createContainer(params=>{
82 | return {
83 | pendingOrders: Meteor.collection('orders').find({status: "pending"}),
84 | };
85 | }, Orders)
86 | ```
87 |
88 | # connectMeteor && getMeteorData
89 |
90 | connectMeteor is a React Mixin which enables getMeteorData (the old way of populating meteor data into your components).
91 |
92 | ## Example
93 |
94 | ```javascript
95 | import Meteor, { connectMeteor } from 'electron-meteor';
96 |
97 | /*
98 | * Uses decorators (see detailed installation to activate it)
99 | * Or use :
100 |
101 | class Todos extends Component {
102 | ...
103 | }
104 | connectMeteor(Todos);
105 | export default Todos;
106 |
107 | */
108 |
109 | @connectMeteor
110 | class Orders extends Component {
111 | getMeteorData() {
112 | return {
113 | pendingOrders: Meteor.collection('orders').find({status: "pending"}),
114 | };
115 | }
116 | render() {
117 | const { pendingOrders } = this.props;
118 |
119 | //...
120 | );
121 | }
122 | }
123 | ```
124 |
125 | # Reactive variables
126 |
127 | These variables can be used inside getMeteorData or createContainer. They will be populated into your component if they change.
128 |
129 | * [Meteor.subscribe](http://docs.meteor.com/#/full/meteor_subscribe) : returns an handle. !! If the component which called subscribe is unmounted, the subscription is automatically canceled.
130 | * Meteor.collection(collectionName)
131 | * [.find(selector, options)](http://docs.meteor.com/#/full/find)
132 | * [.findOne(selector, options)](http://docs.meteor.com/#/full/findone)
133 | * [Meteor.user()](http://docs.meteor.com/#/full/meteor_user)
134 | * [Meteor.userId()](http://docs.meteor.com/#/full/meteor_userid)
135 | * [Meteor.status()](http://docs.meteor.com/#/full/meteor_status)
136 | * [Meteor.loggingIn()](http://docs.meteor.com/#/full/meteor_loggingin)
137 |
138 | # Additionals collection methods
139 |
140 | These methods (except update) work offline. That means that elements are correctly updated offline, and when you reconnect to ddp, Meteor calls are taken care of.
141 |
142 | * Meteor.collection(collectionName)
143 | * [.insert(doc, callback)](http://docs.meteor.com/#/full/insert)
144 | * [.update(id, modifier, [options], [callback])](http://docs.meteor.com/#/full/update)
145 | * [.remove(id, callback(err, countRemoved))](http://docs.meteor.com/#/full/remove)
146 |
147 |
148 | # MeteorListView Component
149 |
150 | Same as [ListView](https://facebook.github.io/react-native/docs/listview.html) Component but does not need dataSource and accepts three arguments :
151 |
152 | - `collection` **string** *required*
153 | - `selector` [**string** / **object**]
154 | - `options` **object**
155 | - `listViewRef` [**string** / **function**] ref to ListView component.
156 |
157 |
158 | ### Example usage
159 |
160 | ```javascript
161 |
168 | ```
169 |
170 | # MeteorComplexListView Component
171 |
172 | Same as [ListView](https://facebook.github.io/react-native/docs/listview.html) Component but does not need dataSource and accepts one argument. You may need it if you make complex requests combining multiples collections.
173 |
174 | - `elements` **function** *required* : a reactive function which returns an array of elements.
175 | - `listViewRef` [**string** / **function**] ref to ListView component.
176 |
177 | ### Example usage
178 |
179 | ```javascript
180 | {return Meteor.collection('todos').find()}}
182 | renderRow={this.renderItem}
183 | //...other listview props
184 | />
185 | ```
186 |
187 | # API
188 |
189 | ## Meteor DDP connection
190 |
191 | #### Meteor.connect(endpoint, options)
192 |
193 | Connect to a DDP server. You only have to do this once in your app.
194 |
195 | #### Arguments
196 |
197 | - `url` **string** *required*
198 | - `options` **object** Available options are :
199 | - autoConnect **boolean** [true] whether to establish the connection to the server upon instantiation. When false, one can manually establish the connection with the Meteor.ddp.connect method.
200 | - autoReconnect **boolean** [true] whether to try to reconnect to the server when the socket connection closes, unless the closing was initiated by a call to the disconnect method.
201 | - reconnectInterval **number** [10000] the interval in ms between reconnection attempts.
202 |
203 | #### Meteor.disconnect()
204 |
205 | Disconnect from the DDP server.
206 |
207 | ## Meteor methods
208 |
209 | * [Meteor.call](http://docs.meteor.com/#/full/meteor_call)
210 | * [Meteor.loginWithPassword](http://docs.meteor.com/#/full/meteor_loginwithpassword) (Please note that user is auto-resigned in - like in Meteor Web applications - thanks to React Native AsyncStorage.)
211 | * [Meteor.logout](http://docs.meteor.com/#/full/meteor_logout)
212 | * [Meteor.logoutOtherClients](http://docs.meteor.com/#/full/meteor_logoutotherclients)
213 |
214 | ## Meteor.Accounts
215 |
216 | * [Accounts.createUser](http://docs.meteor.com/#/full/accounts_createuser)
217 | * [Accounts.changePassword](http://docs.meteor.com/#/full/accounts_forgotpassword)
218 | * [Accounts.forgotPassword](http://docs.meteor.com/#/full/accounts_changepassword)
219 | * [Accounts.onLogin](http://docs.meteor.com/#/full/accounts_onlogin)
220 | * [Accounts.onLoginFailure](http://docs.meteor.com/#/full/accounts_onloginfailure)
221 |
222 | ## Meteor.ddp
223 |
224 | Once connected to the ddp server, you can access every method available in [ddp.js](https://github.com/mondora/ddp.js/).
225 | * Meteor.ddp.on('connected')
226 | * Meteor.ddp.on('added')
227 | * Meteor.ddp.on('changed')
228 | * ...
229 |
230 | ## CollectionFS
231 |
232 | * Meteor.FSCollection(collectionName) : Helper for [Meteor-CollectionFS](https://github.com/CollectionFS/Meteor-CollectionFS). Full documentation [here](https://github.com/inProgress-team/electron-meteor/blob/master/docs/FSCollection.md)
233 | * This plugin also exposes a FSCollectionImagesPreloader component which helps you preload every image you want in CollectionFS (only available on ios)
234 |
235 | ```javascript
236 | import { FSCollectionImagesPreloader } from 'electron-meteor';
237 |
238 |
242 | ```
243 |
244 |
245 | ## react-native-router-flux
246 |
247 | * [Github repository](https://github.com/inProgress-team/electron-meteor-router-flux)
248 | * npm i --save electron-meteor-router-flux@latest
249 | * [Custom scene renderer](https://github.com/aksonov/react-native-router-flux#switch-new-feature) which allows to select tab scene to show depending from app state. It could be useful for authentication, restricted scenes, etc.
250 |
251 |
252 | # Want to help ?
253 |
254 | Pull Requests and issues reported are welcome ! :)
255 |
--------------------------------------------------------------------------------
/dist/src/components/Mixin.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 |
7 | var _typeof2 = require('babel-runtime/helpers/typeof');
8 |
9 | var _typeof3 = _interopRequireDefault(_typeof2);
10 |
11 | var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
12 |
13 | var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
14 |
15 | var _createClass2 = require('babel-runtime/helpers/createClass');
16 |
17 | var _createClass3 = _interopRequireDefault(_createClass2);
18 |
19 | var _trackr = require('trackr');
20 |
21 | var _trackr2 = _interopRequireDefault(_trackr);
22 |
23 | var _ejson = require('ejson');
24 |
25 | var _ejson2 = _interopRequireDefault(_ejson);
26 |
27 | var _Data = require('../Data');
28 |
29 | var _Data2 = _interopRequireDefault(_Data);
30 |
31 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
32 |
33 | exports.default = {
34 | componentWillMount: function componentWillMount() {
35 | var _this = this;
36 |
37 | _Data2.default.waitDdpReady(function () {
38 | if (_this.getMeteorData) {
39 | _this.data = {};
40 | _this._meteorDataManager = new MeteorDataManager(_this);
41 | var newData = _this._meteorDataManager.calculateData();
42 | _this._meteorDataManager.updateData(newData);
43 | }
44 |
45 | if (_this.startMeteorSubscriptions) {
46 | console.warn('startMeteorSubscriptions is deprecated and will be removed soon. Please create your subscriptions in getMeteorData.');
47 | _this._meteorSubscriptionsManager = new MeteorSubscriptionsManager(_this);
48 | _this._meteorSubscriptionsManager.getMeteorSubscriptions();
49 | }
50 | });
51 | },
52 | componentWillUpdate: function componentWillUpdate(nextProps, nextState) {
53 |
54 | if (this.startMeteorSubscriptions) {
55 | if (!_ejson2.default.equals(this.state, nextState) || !_ejson2.default.equals(this.props, nextProps)) {
56 | this._meteorSubscriptionsManager._meteorDataChangedCallback();
57 | }
58 | }
59 |
60 | if (this.getMeteorData) {
61 | var saveProps = this.props;
62 | var saveState = this.state;
63 | var newData = void 0;
64 | try {
65 | // Temporarily assign this.state and this.props,
66 | // so that they are seen by getMeteorData!
67 | // This is a simulation of how the proposed Observe API
68 | // for React will work, which calls observe() after
69 | // componentWillUpdate and after props and state are
70 | // updated, but before render() is called.
71 | // See https://github.com/facebook/react/issues/3398.
72 | this.props = nextProps;
73 | this.state = nextState;
74 | newData = this._meteorDataManager.calculateData();
75 | } finally {
76 | this.props = saveProps;
77 | this.state = saveState;
78 | }
79 |
80 | this._meteorDataManager.updateData(newData);
81 | }
82 | },
83 | componentWillUnmount: function componentWillUnmount() {
84 | if (this._meteorDataManager) {
85 | this._meteorDataManager.dispose();
86 | }
87 |
88 | if (this._meteorSubscriptionsManager) {
89 | this._meteorSubscriptionsManager.dispose();
90 | }
91 | }
92 | };
93 |
94 | var MeteorSubscriptionsManager = function () {
95 | function MeteorSubscriptionsManager(component) {
96 | var _this2 = this;
97 |
98 | (0, _classCallCheck3.default)(this, MeteorSubscriptionsManager);
99 |
100 | this.component = component;
101 | this.computation = null;
102 |
103 | this._meteorSubscriptionsDep = new _trackr2.default.Dependency();
104 |
105 | this._meteorDataChangedCallback = function () {
106 | _this2._meteorSubscriptionsDep.changed();
107 | };
108 |
109 | _Data2.default.onChange(this._meteorDataChangedCallback);
110 | }
111 |
112 | (0, _createClass3.default)(MeteorSubscriptionsManager, [{
113 | key: 'dispose',
114 | value: function dispose() {
115 | if (this.computation) {
116 | this.computation.stop();
117 | this.computation = null;
118 | }
119 |
120 | _Data2.default.offChange(this._meteorDataChangedCallback);
121 | }
122 | }, {
123 | key: 'stateOrPropsChanged',
124 | value: function stateOrPropsChanged() {}
125 | }, {
126 | key: 'getMeteorSubscriptions',
127 | value: function getMeteorSubscriptions() {
128 | var _this3 = this;
129 |
130 | this.computation = _trackr2.default.nonreactive(function () {
131 | return _trackr2.default.autorun(function (c) {
132 | _this3._meteorSubscriptionsDep.depend();
133 |
134 | _this3.component.startMeteorSubscriptions();
135 | });
136 | });
137 | }
138 | }]);
139 | return MeteorSubscriptionsManager;
140 | }();
141 |
142 | // A class to keep the state and utility methods needed to manage
143 | // the Meteor data for a component.
144 |
145 |
146 | var MeteorDataManager = function () {
147 | function MeteorDataManager(component) {
148 | var _this4 = this;
149 |
150 | (0, _classCallCheck3.default)(this, MeteorDataManager);
151 |
152 | this.component = component;
153 | this.computation = null;
154 | this.oldData = null;
155 | this._meteorDataDep = new _trackr2.default.Dependency();
156 |
157 | this._meteorDataChangedCallback = function () {
158 | _this4._meteorDataDep.changed();
159 | };
160 |
161 | _Data2.default.onChange(this._meteorDataChangedCallback);
162 | }
163 |
164 | (0, _createClass3.default)(MeteorDataManager, [{
165 | key: 'dispose',
166 | value: function dispose() {
167 | if (this.computation) {
168 | this.computation.stop();
169 | this.computation = null;
170 | }
171 |
172 | _Data2.default.offChange(this._meteorDataChangedCallback);
173 | }
174 | }, {
175 | key: 'calculateData',
176 | value: function calculateData() {
177 | var _this5 = this;
178 |
179 | var component = this.component;
180 |
181 | if (!component.getMeteorData) {
182 | return null;
183 | }
184 |
185 | if (this.computation) {
186 | this.computation.stop();
187 | this.computation = null;
188 | }
189 |
190 | var data = void 0;
191 | // Use Tracker.nonreactive in case we are inside a Tracker Computation.
192 | // This can happen if someone calls `ReactDOM.render` inside a Computation.
193 | // In that case, we want to opt out of the normal behavior of nested
194 | // Computations, where if the outer one is invalidated or stopped,
195 | // it stops the inner one.
196 |
197 | this.computation = _trackr2.default.nonreactive(function () {
198 | return _trackr2.default.autorun(function (c) {
199 | _this5._meteorDataDep.depend();
200 | if (c.firstRun) {
201 | var savedSetState = component.setState;
202 | try {
203 | component.setState = function () {
204 | throw new Error("Can't call `setState` inside `getMeteorData` as this could cause an endless" + " loop. To respond to Meteor data changing, consider making this component" + " a \"wrapper component\" that only fetches data and passes it in as props to" + " a child component. Then you can use `componentWillReceiveProps` in that" + " child component.");
205 | };
206 |
207 | data = component.getMeteorData();
208 | } finally {
209 | component.setState = savedSetState;
210 | }
211 | } else {
212 | // Stop this computation instead of using the re-run.
213 | // We use a brand-new autorun for each call to getMeteorData
214 | // to capture dependencies on any reactive data sources that
215 | // are accessed. The reason we can't use a single autorun
216 | // for the lifetime of the component is that Tracker only
217 | // re-runs autoruns at flush time, while we need to be able to
218 | // re-call getMeteorData synchronously whenever we want, e.g.
219 | // from componentWillUpdate.
220 | c.stop();
221 | // Calling forceUpdate() triggers componentWillUpdate which
222 | // recalculates getMeteorData() and re-renders the component.
223 | component.forceUpdate();
224 | }
225 | });
226 | });
227 |
228 | return data;
229 | }
230 | }, {
231 | key: 'updateData',
232 | value: function updateData(newData) {
233 | var component = this.component;
234 | var oldData = this.oldData;
235 |
236 | if (!(newData && (typeof newData === 'undefined' ? 'undefined' : (0, _typeof3.default)(newData)) === 'object')) {
237 | throw new Error("Expected object returned from getMeteorData");
238 | }
239 | // update componentData in place based on newData
240 | for (var key in newData) {
241 | component.data[key] = newData[key];
242 | }
243 | // if there is oldData (which is every time this method is called
244 | // except the first), delete keys in newData that aren't in
245 | // oldData. don't interfere with other keys, in case we are
246 | // co-existing with something else that writes to a component's
247 | // this.data.
248 | if (oldData) {
249 | for (var _key in oldData) {
250 | if (!(_key in newData)) {
251 | delete component.data[_key];
252 | }
253 | }
254 | }
255 | this.oldData = newData;
256 | }
257 | }]);
258 | return MeteorDataManager;
259 | }();
--------------------------------------------------------------------------------
/dist/components/Mixin.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 |
7 | var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; };
8 |
9 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
10 |
11 | var _trackr = require('trackr');
12 |
13 | var _trackr2 = _interopRequireDefault(_trackr);
14 |
15 | var _ejson = require('ejson');
16 |
17 | var _ejson2 = _interopRequireDefault(_ejson);
18 |
19 | var _Data = require('../Data');
20 |
21 | var _Data2 = _interopRequireDefault(_Data);
22 |
23 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
24 |
25 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
26 |
27 | exports.default = {
28 | componentWillMount: function componentWillMount() {
29 | var _this = this;
30 |
31 | _Data2.default.waitDdpReady(function () {
32 | if (_this.getMeteorData) {
33 | _this.data = {};
34 | _this._meteorDataManager = new MeteorDataManager(_this);
35 | var newData = _this._meteorDataManager.calculateData();
36 | _this._meteorDataManager.updateData(newData);
37 | }
38 |
39 | if (_this.startMeteorSubscriptions) {
40 | console.warn('startMeteorSubscriptions is deprecated and will be removed soon. Please create your subscriptions in getMeteorData.');
41 | _this._meteorSubscriptionsManager = new MeteorSubscriptionsManager(_this);
42 | _this._meteorSubscriptionsManager.getMeteorSubscriptions();
43 | }
44 | });
45 | },
46 | componentWillUpdate: function componentWillUpdate(nextProps, nextState) {
47 |
48 | if (this.startMeteorSubscriptions) {
49 | if (!_ejson2.default.equals(this.state, nextState) || !_ejson2.default.equals(this.props, nextProps)) {
50 | this._meteorSubscriptionsManager._meteorDataChangedCallback();
51 | }
52 | }
53 |
54 | if (this.getMeteorData) {
55 | var saveProps = this.props;
56 | var saveState = this.state;
57 | var newData = void 0;
58 | try {
59 | // Temporarily assign this.state and this.props,
60 | // so that they are seen by getMeteorData!
61 | // This is a simulation of how the proposed Observe API
62 | // for React will work, which calls observe() after
63 | // componentWillUpdate and after props and state are
64 | // updated, but before render() is called.
65 | // See https://github.com/facebook/react/issues/3398.
66 | this.props = nextProps;
67 | this.state = nextState;
68 | newData = this._meteorDataManager.calculateData();
69 | } finally {
70 | this.props = saveProps;
71 | this.state = saveState;
72 | }
73 |
74 | this._meteorDataManager.updateData(newData);
75 | }
76 | },
77 | componentWillUnmount: function componentWillUnmount() {
78 | if (this._meteorDataManager) {
79 | this._meteorDataManager.dispose();
80 | }
81 |
82 | if (this._meteorSubscriptionsManager) {
83 | this._meteorSubscriptionsManager.dispose();
84 | }
85 | }
86 | };
87 |
88 | var MeteorSubscriptionsManager = function () {
89 | function MeteorSubscriptionsManager(component) {
90 | var _this2 = this;
91 |
92 | _classCallCheck(this, MeteorSubscriptionsManager);
93 |
94 | this.component = component;
95 | this.computation = null;
96 |
97 | this._meteorSubscriptionsDep = new _trackr2.default.Dependency();
98 |
99 | this._meteorDataChangedCallback = function () {
100 | _this2._meteorSubscriptionsDep.changed();
101 | };
102 |
103 | _Data2.default.onChange(this._meteorDataChangedCallback);
104 | }
105 |
106 | _createClass(MeteorSubscriptionsManager, [{
107 | key: 'dispose',
108 | value: function dispose() {
109 | if (this.computation) {
110 | this.computation.stop();
111 | this.computation = null;
112 | }
113 |
114 | _Data2.default.offChange(this._meteorDataChangedCallback);
115 | }
116 | }, {
117 | key: 'stateOrPropsChanged',
118 | value: function stateOrPropsChanged() {}
119 | }, {
120 | key: 'getMeteorSubscriptions',
121 | value: function getMeteorSubscriptions() {
122 | var _this3 = this;
123 |
124 | this.computation = _trackr2.default.nonreactive(function () {
125 | return _trackr2.default.autorun(function (c) {
126 | _this3._meteorSubscriptionsDep.depend();
127 |
128 | _this3.component.startMeteorSubscriptions();
129 | });
130 | });
131 | }
132 | }]);
133 |
134 | return MeteorSubscriptionsManager;
135 | }();
136 |
137 | // A class to keep the state and utility methods needed to manage
138 | // the Meteor data for a component.
139 |
140 |
141 | var MeteorDataManager = function () {
142 | function MeteorDataManager(component) {
143 | var _this4 = this;
144 |
145 | _classCallCheck(this, MeteorDataManager);
146 |
147 | this.component = component;
148 | this.computation = null;
149 | this.oldData = null;
150 | this._meteorDataDep = new _trackr2.default.Dependency();
151 |
152 | this._meteorDataChangedCallback = function () {
153 | _this4._meteorDataDep.changed();
154 | };
155 |
156 | _Data2.default.onChange(this._meteorDataChangedCallback);
157 | }
158 |
159 | _createClass(MeteorDataManager, [{
160 | key: 'dispose',
161 | value: function dispose() {
162 | if (this.computation) {
163 | this.computation.stop();
164 | this.computation = null;
165 | }
166 |
167 | _Data2.default.offChange(this._meteorDataChangedCallback);
168 | }
169 | }, {
170 | key: 'calculateData',
171 | value: function calculateData() {
172 | var _this5 = this;
173 |
174 | var component = this.component;
175 |
176 | if (!component.getMeteorData) {
177 | return null;
178 | }
179 |
180 | if (this.computation) {
181 | this.computation.stop();
182 | this.computation = null;
183 | }
184 |
185 | var data = void 0;
186 | // Use Tracker.nonreactive in case we are inside a Tracker Computation.
187 | // This can happen if someone calls `ReactDOM.render` inside a Computation.
188 | // In that case, we want to opt out of the normal behavior of nested
189 | // Computations, where if the outer one is invalidated or stopped,
190 | // it stops the inner one.
191 |
192 | this.computation = _trackr2.default.nonreactive(function () {
193 | return _trackr2.default.autorun(function (c) {
194 | _this5._meteorDataDep.depend();
195 | if (c.firstRun) {
196 | var savedSetState = component.setState;
197 | try {
198 | component.setState = function () {
199 | throw new Error("Can't call `setState` inside `getMeteorData` as this could cause an endless" + " loop. To respond to Meteor data changing, consider making this component" + " a \"wrapper component\" that only fetches data and passes it in as props to" + " a child component. Then you can use `componentWillReceiveProps` in that" + " child component.");
200 | };
201 |
202 | data = component.getMeteorData();
203 | } finally {
204 | component.setState = savedSetState;
205 | }
206 | } else {
207 | // Stop this computation instead of using the re-run.
208 | // We use a brand-new autorun for each call to getMeteorData
209 | // to capture dependencies on any reactive data sources that
210 | // are accessed. The reason we can't use a single autorun
211 | // for the lifetime of the component is that Tracker only
212 | // re-runs autoruns at flush time, while we need to be able to
213 | // re-call getMeteorData synchronously whenever we want, e.g.
214 | // from componentWillUpdate.
215 | c.stop();
216 | // Calling forceUpdate() triggers componentWillUpdate which
217 | // recalculates getMeteorData() and re-renders the component.
218 | component.forceUpdate();
219 | }
220 | });
221 | });
222 |
223 | return data;
224 | }
225 | }, {
226 | key: 'updateData',
227 | value: function updateData(newData) {
228 | var component = this.component;
229 | var oldData = this.oldData;
230 |
231 | if (!(newData && (typeof newData === 'undefined' ? 'undefined' : _typeof(newData)) === 'object')) {
232 | throw new Error("Expected object returned from getMeteorData");
233 | }
234 | // update componentData in place based on newData
235 | for (var key in newData) {
236 | component.data[key] = newData[key];
237 | }
238 | // if there is oldData (which is every time this method is called
239 | // except the first), delete keys in newData that aren't in
240 | // oldData. don't interfere with other keys, in case we are
241 | // co-existing with something else that writes to a component's
242 | // this.data.
243 | if (oldData) {
244 | for (var _key in oldData) {
245 | if (!(_key in newData)) {
246 | delete component.data[_key];
247 | }
248 | }
249 | }
250 | this.oldData = newData;
251 | }
252 | }]);
253 |
254 | return MeteorDataManager;
255 | }();
--------------------------------------------------------------------------------
/dist/Meteor.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
4 | //import FSCollectionImagesPreloader from './CollectionFS/FSCollectionImagesPreloader';
5 |
6 | var _reactNative = require('react-native');
7 |
8 | var _reactMixin = require('react-mixin');
9 |
10 | var _reactMixin2 = _interopRequireDefault(_reactMixin);
11 |
12 | var _trackr = require('trackr');
13 |
14 | var _trackr2 = _interopRequireDefault(_trackr);
15 |
16 | var _ejson = require('ejson');
17 |
18 | var _ejson2 = _interopRequireDefault(_ejson);
19 |
20 | var _ddp = require('../lib/ddp.js');
21 |
22 | var _ddp2 = _interopRequireDefault(_ddp);
23 |
24 | var _Random = require('../lib/Random');
25 |
26 | var _Random2 = _interopRequireDefault(_Random);
27 |
28 | var _Data = require('./Data');
29 |
30 | var _Data2 = _interopRequireDefault(_Data);
31 |
32 | var _Collection = require('./Collection');
33 |
34 | var _Collection2 = _interopRequireDefault(_Collection);
35 |
36 | var _Call = require('./Call');
37 |
38 | var _Call2 = _interopRequireDefault(_Call);
39 |
40 | var _Mixin = require('./components/Mixin');
41 |
42 | var _Mixin2 = _interopRequireDefault(_Mixin);
43 |
44 | var _createContainer = require('./components/createContainer');
45 |
46 | var _createContainer2 = _interopRequireDefault(_createContainer);
47 |
48 | var _FSCollection = require('./CollectionFS/FSCollection');
49 |
50 | var _FSCollection2 = _interopRequireDefault(_FSCollection);
51 |
52 | var _User = require('./user/User');
53 |
54 | var _User2 = _interopRequireDefault(_User);
55 |
56 | var _Accounts = require('./user/Accounts');
57 |
58 | var _Accounts2 = _interopRequireDefault(_Accounts);
59 |
60 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
61 |
62 | module.exports = {
63 | Accounts: _Accounts2.default,
64 | //FSCollectionImagesPreloader: Platform.OS == 'android' ? View : FSCollectionImagesPreloader,
65 | collection: _Collection2.default,
66 | FSCollection: _FSCollection2.default,
67 | createContainer: _createContainer2.default,
68 | getData: function getData() {
69 | return _Data2.default;
70 | },
71 | connectMeteor: function connectMeteor(reactClass) {
72 | return _reactMixin2.default.onClass(reactClass, _Mixin2.default);
73 | },
74 |
75 | User: _User2.default,
76 | status: function status() {
77 | return {
78 | connected: _Data2.default.ddp ? _Data2.default.ddp.status == "connected" : false,
79 | status: _Data2.default.ddp ? _Data2.default.ddp.status : "disconnected"
80 | //retryCount: 0
81 | //retryTime:
82 | //reason:
83 | };
84 | },
85 |
86 | call: _Call2.default,
87 | disconnect: function disconnect() {
88 | if (_Data2.default.ddp) {
89 | _Data2.default.ddp.disconnect();
90 | }
91 | },
92 | _subscriptionsRestart: function _subscriptionsRestart() {
93 |
94 | for (var i in _Data2.default.subscriptions) {
95 | var sub = _Data2.default.subscriptions[i];
96 | _Data2.default.ddp.unsub(sub.subIdRemember);
97 | sub.subIdRemember = _Data2.default.ddp.sub(sub.name, sub.params);
98 | }
99 | },
100 | waitDdpConnected: function waitDdpConnected(cb) {
101 | var _this = this;
102 |
103 | if (_Data2.default.ddp && _Data2.default.ddp.status == 'connected') {
104 | cb();
105 | } else if (_Data2.default.ddp) {
106 | _Data2.default.ddp.once('connected', cb);
107 | } else {
108 | setTimeout(function () {
109 | _this.waitDdpConnected(cb);
110 | }, 10);
111 | }
112 | },
113 | reconnect: function reconnect() {
114 | _Data2.default.ddp && _Data2.default.ddp.connect();
115 | },
116 | connect: function connect(endpoint, options) {
117 | var _this2 = this;
118 |
119 | if (!endpoint) endpoint = _Data2.default._endpoint;
120 | if (!options) options = _Data2.default._options;
121 |
122 | _Data2.default._endpoint = endpoint;
123 | _Data2.default._options = options;
124 |
125 | this.ddp = _Data2.default.ddp = new _ddp2.default(_extends({
126 | endpoint: endpoint,
127 | SocketConstructor: WebSocket
128 | }, options));
129 |
130 | //TODO
131 | /*
132 | NetInfo.isConnected.addEventListener('change', isConnected=>{
133 | if(isConnected) {
134 | Data.ddp.connect();
135 | }
136 | });
137 | */
138 |
139 | _Data2.default.ddp.on("connected", function () {
140 | console.info("Connected to DDP server.");
141 | _this2._loadInitialUser();
142 |
143 | _this2._subscriptionsRestart();
144 | });
145 |
146 | var lastDisconnect = null;
147 | _Data2.default.ddp.on("disconnected", function () {
148 | console.info("Disconnected from DDP server.");
149 |
150 | if (!lastDisconnect || new Date() - lastDisconnect > 3000) {
151 | _Data2.default.ddp.connect();
152 | }
153 |
154 | lastDisconnect = new Date();
155 | });
156 |
157 | _Data2.default.ddp.on("added", function (message) {
158 | if (!_Data2.default.db[message.collection]) {
159 | _Data2.default.db.addCollection(message.collection);
160 | }
161 | _Data2.default.db[message.collection].upsert(_extends({ _id: message.id }, message.fields));
162 | });
163 |
164 | _Data2.default.ddp.on("ready", function (message) {
165 |
166 | for (var i in _Data2.default.subscriptions) {
167 | var sub = _Data2.default.subscriptions[i];
168 | sub.ready = true;
169 | sub.readyDeps.changed();
170 | sub.readyCallback && sub.readyCallback();
171 | }
172 | });
173 |
174 | _Data2.default.ddp.on("changed", function (message) {
175 | _Data2.default.db[message.collection].upsert(_extends({ _id: message.id }, message.fields));
176 | });
177 |
178 | _Data2.default.ddp.on("removed", function (message) {
179 | _Data2.default.db[message.collection].del(message.id);
180 | });
181 | _Data2.default.ddp.on("result", function (message) {
182 | var call = _Data2.default.calls.find(function (call) {
183 | return call.id == message.id;
184 | });
185 | if (typeof call.callback == 'function') call.callback(message.error, message.result);
186 | _Data2.default.calls.splice(_Data2.default.calls.findIndex(function (call) {
187 | return call.id == message.id;
188 | }), 1);
189 | });
190 |
191 | _Data2.default.ddp.on("nosub", function (message) {
192 | for (var i in _Data2.default.subscriptions) {
193 | var sub = _Data2.default.subscriptions[i];
194 | if (sub.subIdRemember == message.id) {
195 | console.warn("No subscription existing for", sub.name);
196 | }
197 | }
198 | });
199 | },
200 | subscribe: function subscribe(name) {
201 | var params = Array.prototype.slice.call(arguments, 1);
202 | var callbacks = {};
203 | if (params.length) {
204 | var lastParam = params[params.length - 1];
205 | if (typeof lastParam == 'function') {
206 | callbacks.onReady = params.pop();
207 | } else if (lastParam && (typeof lastParam.onReady == 'function' || typeof lastParam.onError == 'function' || typeof lastParam.onStop == 'function')) {
208 | callbacks = params.pop();
209 | }
210 | }
211 |
212 | // Is there an existing sub with the same name and param, run in an
213 | // invalidated Computation? This will happen if we are rerunning an
214 | // existing computation.
215 | //
216 | // For example, consider a rerun of:
217 | //
218 | // Tracker.autorun(function () {
219 | // Meteor.subscribe("foo", Session.get("foo"));
220 | // Meteor.subscribe("bar", Session.get("bar"));
221 | // });
222 | //
223 | // If "foo" has changed but "bar" has not, we will match the "bar"
224 | // subcribe to an existing inactive subscription in order to not
225 | // unsub and resub the subscription unnecessarily.
226 | //
227 | // We only look for one such sub; if there are N apparently-identical subs
228 | // being invalidated, we will require N matching subscribe calls to keep
229 | // them all active.
230 |
231 | var existing = false;
232 | for (var i in _Data2.default.subscriptions) {
233 | var sub = _Data2.default.subscriptions[i];
234 | if (sub.inactive && sub.name === name && _ejson2.default.equals(sub.params, params)) existing = sub;
235 | }
236 |
237 | var id = void 0;
238 | if (existing) {
239 | id = existing.id;
240 | existing.inactive = false;
241 |
242 | if (callbacks.onReady) {
243 | // If the sub is not already ready, replace any ready callback with the
244 | // one provided now. (It's not really clear what users would expect for
245 | // an onReady callback inside an autorun; the semantics we provide is
246 | // that at the time the sub first becomes ready, we call the last
247 | // onReady callback provided, if any.)
248 | if (!existing.ready) existing.readyCallback = callbacks.onReady;
249 | }
250 | if (callbacks.onStop) {
251 | existing.stopCallback = callbacks.onStop;
252 | }
253 | } else {
254 |
255 | // New sub! Generate an id, save it locally, and send message.
256 |
257 | id = _Random2.default.id();
258 | var subIdRemember = _Data2.default.ddp.sub(name, params);
259 |
260 | _Data2.default.subscriptions[id] = {
261 | id: id,
262 | subIdRemember: subIdRemember,
263 | name: name,
264 | params: _ejson2.default.clone(params),
265 | inactive: false,
266 | ready: false,
267 | readyDeps: new _trackr2.default.Dependency(),
268 | readyCallback: callbacks.onReady,
269 | stopCallback: callbacks.onStop,
270 | stop: function stop() {
271 | _Data2.default.ddp.unsub(this.subIdRemember);
272 | delete _Data2.default.subscriptions[this.id];
273 | this.ready && this.readyDeps.changed();
274 |
275 | if (callbacks.onStop) {
276 | callbacks.onStop();
277 | }
278 | }
279 | };
280 | }
281 |
282 | // return a handle to the application.
283 | var handle = {
284 | stop: function stop() {
285 | if (_Data2.default.subscriptions[id]) _Data2.default.subscriptions[id].stop();
286 | },
287 | ready: function ready() {
288 | if (!_Data2.default.subscriptions[id]) return false;
289 |
290 | var record = _Data2.default.subscriptions[id];
291 | record.readyDeps.depend();
292 | return record.ready;
293 | },
294 | subscriptionId: id
295 | };
296 |
297 | if (_trackr2.default.active) {
298 | // We're in a reactive computation, so we'd like to unsubscribe when the
299 | // computation is invalidated... but not if the rerun just re-subscribes
300 | // to the same subscription! When a rerun happens, we use onInvalidate
301 | // as a change to mark the subscription "inactive" so that it can
302 | // be reused from the rerun. If it isn't reused, it's killed from
303 | // an afterFlush.
304 | _trackr2.default.onInvalidate(function (c) {
305 | if (_Data2.default.subscriptions[id]) {
306 | _Data2.default.subscriptions[id].inactive = true;
307 | }
308 |
309 | _trackr2.default.afterFlush(function () {
310 | if (_Data2.default.subscriptions[id] && _Data2.default.subscriptions[id].inactive) {
311 | handle.stop();
312 | }
313 | });
314 | });
315 | }
316 |
317 | return handle;
318 | }
319 | };
--------------------------------------------------------------------------------
/dist/src/Meteor.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var _extends2 = require('babel-runtime/helpers/extends');
4 |
5 | var _extends3 = _interopRequireDefault(_extends2);
6 |
7 | var _reactMixin = require('react-mixin');
8 |
9 | var _reactMixin2 = _interopRequireDefault(_reactMixin);
10 |
11 | var _trackr = require('trackr');
12 |
13 | var _trackr2 = _interopRequireDefault(_trackr);
14 |
15 | var _ejson = require('ejson');
16 |
17 | var _ejson2 = _interopRequireDefault(_ejson);
18 |
19 | var _ddp = require('../lib/ddp.js');
20 |
21 | var _ddp2 = _interopRequireDefault(_ddp);
22 |
23 | var _Random = require('../lib/Random');
24 |
25 | var _Random2 = _interopRequireDefault(_Random);
26 |
27 | var _Data = require('./Data');
28 |
29 | var _Data2 = _interopRequireDefault(_Data);
30 |
31 | var _Collection = require('./Collection');
32 |
33 | var _Collection2 = _interopRequireDefault(_Collection);
34 |
35 | var _Call = require('./Call');
36 |
37 | var _Call2 = _interopRequireDefault(_Call);
38 |
39 | var _Mixin = require('./components/Mixin');
40 |
41 | var _Mixin2 = _interopRequireDefault(_Mixin);
42 |
43 | var _createContainer = require('./components/createContainer');
44 |
45 | var _createContainer2 = _interopRequireDefault(_createContainer);
46 |
47 | var _FSCollection = require('./CollectionFS/FSCollection');
48 |
49 | var _FSCollection2 = _interopRequireDefault(_FSCollection);
50 |
51 | var _FSCollectionImagesPreloader = require('./CollectionFS/FSCollectionImagesPreloader');
52 |
53 | var _FSCollectionImagesPreloader2 = _interopRequireDefault(_FSCollectionImagesPreloader);
54 |
55 | var _User = require('./user/User');
56 |
57 | var _User2 = _interopRequireDefault(_User);
58 |
59 | var _Accounts = require('./user/Accounts');
60 |
61 | var _Accounts2 = _interopRequireDefault(_Accounts);
62 |
63 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
64 |
65 | //import { NetInfo } from 'react-native';
66 |
67 | module.exports = (0, _extends3.default)({
68 | Accounts: _Accounts2.default,
69 | FSCollectionImagesPreloader: _FSCollectionImagesPreloader2.default,
70 | collection: _Collection2.default,
71 | FSCollection: _FSCollection2.default,
72 | createContainer: _createContainer2.default,
73 | getData: function getData() {
74 | return _Data2.default;
75 | },
76 | connectMeteor: function connectMeteor(reactClass) {
77 | return _reactMixin2.default.onClass(reactClass, _Mixin2.default);
78 | }
79 | }, _User2.default, {
80 | status: function status() {
81 | return {
82 | connected: _Data2.default.ddp ? _Data2.default.ddp.status == "connected" : false,
83 | status: _Data2.default.ddp ? _Data2.default.ddp.status : "disconnected"
84 | //retryCount: 0
85 | //retryTime:
86 | //reason:
87 | };
88 | },
89 |
90 | call: _Call2.default,
91 | disconnect: function disconnect() {
92 | if (_Data2.default.ddp) {
93 | _Data2.default.ddp.disconnect();
94 | }
95 | },
96 | _subscriptionsRestart: function _subscriptionsRestart() {
97 |
98 | for (var i in _Data2.default.subscriptions) {
99 | var sub = _Data2.default.subscriptions[i];
100 | _Data2.default.ddp.unsub(sub.subIdRemember);
101 | sub.subIdRemember = _Data2.default.ddp.sub(sub.name, sub.params);
102 | }
103 | },
104 | waitDdpConnected: function waitDdpConnected(cb) {
105 | var _this = this;
106 |
107 | if (_Data2.default.ddp && _Data2.default.ddp.status == 'connected') {
108 | cb();
109 | } else if (_Data2.default.ddp) {
110 | _Data2.default.ddp.once('connected', cb);
111 | } else {
112 | setTimeout(function () {
113 | _this.waitDdpConnected(cb);
114 | }, 10);
115 | }
116 | },
117 | reconnect: function reconnect() {
118 | _Data2.default.ddp && _Data2.default.ddp.connect();
119 | },
120 | connect: function connect(endpoint, options) {
121 | var _this2 = this;
122 |
123 | if (!endpoint) endpoint = _Data2.default._endpoint;
124 | if (!options) options = _Data2.default._options;
125 |
126 | _Data2.default._endpoint = endpoint;
127 | _Data2.default._options = options;
128 |
129 | this.ddp = _Data2.default.ddp = new _ddp2.default((0, _extends3.default)({
130 | endpoint: endpoint,
131 | SocketConstructor: WebSocket
132 | }, options));
133 |
134 | this.subscribe('_roles');
135 | //TODO
136 | /*
137 | NetInfo.isConnected.addEventListener('change', isConnected=>{
138 | if(isConnected) {
139 | Data.ddp.connect();
140 | }
141 | });
142 | */
143 |
144 | _Data2.default.ddp.on("connected", function () {
145 | console.info("Connected to DDP server.");
146 | _this2._loadInitialUser();
147 |
148 | _this2._subscriptionsRestart();
149 | });
150 |
151 | var lastDisconnect = null;
152 | _Data2.default.ddp.on("disconnected", function () {
153 | console.info("Disconnected from DDP server.");
154 |
155 | if (!lastDisconnect || new Date() - lastDisconnect > 3000) {
156 | _Data2.default.ddp.connect();
157 | }
158 |
159 | lastDisconnect = new Date();
160 | });
161 |
162 | _Data2.default.ddp.on("added", function (message) {
163 | if (!_Data2.default.db[message.collection]) {
164 | _Data2.default.db.addCollection(message.collection);
165 | }
166 | _Data2.default.db[message.collection].upsert((0, _extends3.default)({ _id: message.id }, message.fields));
167 | });
168 |
169 | _Data2.default.ddp.on("ready", function (message) {
170 |
171 | for (var i in _Data2.default.subscriptions) {
172 | var sub = _Data2.default.subscriptions[i];
173 | sub.ready = true;
174 | sub.readyDeps.changed();
175 | sub.readyCallback && sub.readyCallback();
176 | }
177 | });
178 |
179 | _Data2.default.ddp.on("changed", function (message) {
180 | _Data2.default.db[message.collection].upsert((0, _extends3.default)({ _id: message.id }, message.fields));
181 | });
182 |
183 | _Data2.default.ddp.on("removed", function (message) {
184 | _Data2.default.db[message.collection].del(message.id);
185 | });
186 | _Data2.default.ddp.on("result", function (message) {
187 | var call = _Data2.default.calls.find(function (call) {
188 | return call.id == message.id;
189 | });
190 | if (typeof call.callback == 'function') call.callback(message.error, message.result);
191 | _Data2.default.calls.splice(_Data2.default.calls.findIndex(function (call) {
192 | return call.id == message.id;
193 | }), 1);
194 | });
195 |
196 | _Data2.default.ddp.on("nosub", function (message) {
197 | for (var i in _Data2.default.subscriptions) {
198 | var sub = _Data2.default.subscriptions[i];
199 | if (sub.subIdRemember == message.id) {
200 | console.warn("No subscription existing for", sub.name);
201 | }
202 | }
203 | });
204 | },
205 | subscribe: function subscribe(name) {
206 | var params = Array.prototype.slice.call(arguments, 1);
207 | var callbacks = {};
208 | if (params.length) {
209 | var lastParam = params[params.length - 1];
210 | if (typeof lastParam == 'function') {
211 | callbacks.onReady = params.pop();
212 | } else if (lastParam && (typeof lastParam.onReady == 'function' || typeof lastParam.onError == 'function' || typeof lastParam.onStop == 'function')) {
213 | callbacks = params.pop();
214 | }
215 | }
216 |
217 | // Is there an existing sub with the same name and param, run in an
218 | // invalidated Computation? This will happen if we are rerunning an
219 | // existing computation.
220 | //
221 | // For example, consider a rerun of:
222 | //
223 | // Tracker.autorun(function () {
224 | // Meteor.subscribe("foo", Session.get("foo"));
225 | // Meteor.subscribe("bar", Session.get("bar"));
226 | // });
227 | //
228 | // If "foo" has changed but "bar" has not, we will match the "bar"
229 | // subcribe to an existing inactive subscription in order to not
230 | // unsub and resub the subscription unnecessarily.
231 | //
232 | // We only look for one such sub; if there are N apparently-identical subs
233 | // being invalidated, we will require N matching subscribe calls to keep
234 | // them all active.
235 |
236 | var existing = false;
237 | for (var i in _Data2.default.subscriptions) {
238 | var sub = _Data2.default.subscriptions[i];
239 | if (sub.inactive && sub.name === name && _ejson2.default.equals(sub.params, params)) existing = sub;
240 | }
241 |
242 | var id = void 0;
243 | if (existing) {
244 | id = existing.id;
245 | existing.inactive = false;
246 |
247 | if (callbacks.onReady) {
248 | // If the sub is not already ready, replace any ready callback with the
249 | // one provided now. (It's not really clear what users would expect for
250 | // an onReady callback inside an autorun; the semantics we provide is
251 | // that at the time the sub first becomes ready, we call the last
252 | // onReady callback provided, if any.)
253 | if (!existing.ready) existing.readyCallback = callbacks.onReady;
254 | }
255 | if (callbacks.onStop) {
256 | existing.stopCallback = callbacks.onStop;
257 | }
258 | } else {
259 |
260 | // New sub! Generate an id, save it locally, and send message.
261 |
262 | id = _Random2.default.id();
263 | var subIdRemember = _Data2.default.ddp.sub(name, params);
264 |
265 | _Data2.default.subscriptions[id] = {
266 | id: id,
267 | subIdRemember: subIdRemember,
268 | name: name,
269 | params: _ejson2.default.clone(params),
270 | inactive: false,
271 | ready: false,
272 | readyDeps: new _trackr2.default.Dependency(),
273 | readyCallback: callbacks.onReady,
274 | stopCallback: callbacks.onStop,
275 | stop: function stop() {
276 | _Data2.default.ddp.unsub(this.subIdRemember);
277 | delete _Data2.default.subscriptions[this.id];
278 | this.ready && this.readyDeps.changed();
279 |
280 | if (callbacks.onStop) {
281 | callbacks.onStop();
282 | }
283 | }
284 | };
285 | }
286 |
287 | // return a handle to the application.
288 | var handle = {
289 | stop: function stop() {
290 | if (_Data2.default.subscriptions[id]) _Data2.default.subscriptions[id].stop();
291 | },
292 | ready: function ready() {
293 | if (!_Data2.default.subscriptions[id]) return false;
294 |
295 | var record = _Data2.default.subscriptions[id];
296 | record.readyDeps.depend();
297 | return record.ready;
298 | },
299 | subscriptionId: id
300 | };
301 |
302 | if (_trackr2.default.active) {
303 | // We're in a reactive computation, so we'd like to unsubscribe when the
304 | // computation is invalidated... but not if the rerun just re-subscribes
305 | // to the same subscription! When a rerun happens, we use onInvalidate
306 | // as a change to mark the subscription "inactive" so that it can
307 | // be reused from the rerun. If it isn't reused, it's killed from
308 | // an afterFlush.
309 | _trackr2.default.onInvalidate(function (c) {
310 | if (_Data2.default.subscriptions[id]) {
311 | _Data2.default.subscriptions[id].inactive = true;
312 | }
313 |
314 | _trackr2.default.afterFlush(function () {
315 | if (_Data2.default.subscriptions[id] && _Data2.default.subscriptions[id].inactive) {
316 | handle.stop();
317 | }
318 | });
319 | });
320 | }
321 |
322 | return handle;
323 | }
324 | });
--------------------------------------------------------------------------------