hippo-fw 0.9.8 → 0.9.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/client/hippo/access/subscription-choice-layer.jsx +170 -0
- data/client/hippo/access/subscription-choice-layer/cancel-subscription.jsx +111 -0
- data/client/hippo/access/subscription-choice-layer/payment-form.jsx +154 -0
- data/client/hippo/access/subscription-choice-layer/subscription-choice.scss +29 -0
- data/client/hippo/boot.jsx +1 -1
- data/client/hippo/components/asset.jsx +1 -1
- data/client/hippo/components/asset.scss +1 -0
- data/client/hippo/components/data-table.jsx +36 -38
- data/client/hippo/components/date-time.jsx +25 -9
- data/client/hippo/components/form/api.js +1 -0
- data/client/hippo/components/form/fields.jsx +3 -2
- data/client/hippo/components/form/fields/checkbox-wrapper.jsx +1 -1
- data/client/hippo/components/form/fields/date-wrapper.jsx +1 -1
- data/client/hippo/components/form/fields/email-wrapper.jsx +31 -0
- data/client/hippo/components/form/fields/form-field.scss +8 -0
- data/client/hippo/components/form/fields/label.jsx +5 -7
- data/client/hippo/components/form/fields/select-wrapper.jsx +1 -1
- data/client/hippo/components/form/fields/tags-wrapper.jsx +1 -1
- data/client/hippo/components/form/fields/text-wrapper.jsx +1 -1
- data/client/hippo/components/form/fields/textarea-wrapper.jsx +1 -1
- data/client/hippo/components/form/wrapper.jsx +1 -1
- data/client/hippo/components/grid.js +1 -0
- data/client/hippo/components/master-detail.jsx +1 -1
- data/client/hippo/components/network-activity-overlay.jsx +6 -6
- data/client/hippo/components/payments/field.jsx +64 -0
- data/client/hippo/components/payments/field.scss +18 -0
- data/client/hippo/components/popout-window.jsx +1 -1
- data/client/hippo/components/query-builder.jsx +1 -1
- data/client/hippo/components/query-builder/boolean-picker.jsx +1 -1
- data/client/hippo/components/query-builder/clause-filter.jsx +2 -2
- data/client/hippo/components/query-builder/clause.jsx +16 -10
- data/client/hippo/components/query-builder/date-picker.jsx +1 -1
- data/client/hippo/components/query-builder/query-builder.scss +23 -2
- data/client/hippo/components/record-finder.jsx +5 -2
- data/client/hippo/components/record-finder/query-layer.jsx +1 -1
- data/client/hippo/components/save-button.jsx +1 -1
- data/client/hippo/components/screen.jsx +1 -1
- data/client/hippo/components/text-editor.jsx +82 -40
- data/client/hippo/components/text-editor/renderer.jsx +15 -35
- data/client/hippo/components/text-editor/renderer.scss +15 -0
- data/client/hippo/components/text-editor/text-editor.scss +2 -15
- data/client/hippo/components/text-editor/upload-adapter.js +66 -0
- data/client/hippo/components/time-zone-select.jsx +1 -1
- data/client/hippo/components/tool-tip.jsx +9 -14
- data/client/hippo/components/toolbar.jsx +16 -0
- data/client/hippo/components/warning-notification.jsx +1 -1
- data/client/hippo/extensions/base.js +3 -2
- data/client/hippo/extensions/index.js +1 -1
- data/client/hippo/lib/action_cable.js +8 -0
- data/client/hippo/lib/action_cable/cable.js +47 -0
- data/client/hippo/lib/action_cable/connection.js +192 -0
- data/client/hippo/lib/action_cable/connection_monitor.js +135 -0
- data/client/hippo/lib/action_cable/consumer.js +56 -0
- data/client/hippo/lib/action_cable/subscription.js +98 -0
- data/client/hippo/lib/action_cable/subscriptions.js +129 -0
- data/client/hippo/lib/date-range.js +22 -5
- data/client/hippo/lib/lazy-getter.js +31 -0
- data/client/hippo/lib/util.js +6 -1
- data/client/hippo/models/base.js +8 -3
- data/client/hippo/models/config.js +7 -2
- data/client/hippo/models/date-type.js +14 -0
- data/client/hippo/models/decorators.js +5 -5
- data/client/hippo/models/pub_sub.js +1 -1
- data/client/hippo/models/query/array-result.js +4 -1
- data/client/hippo/models/subscription.js +35 -0
- data/client/hippo/models/sync.js +1 -1
- data/client/hippo/models/tenant.js +14 -1
- data/client/hippo/react/component-not-found.jsx +14 -18
- data/client/hippo/screens/async-loading.jsx +46 -0
- data/client/hippo/screens/definition.js +2 -1
- data/client/hippo/screens/preferences.jsx +57 -0
- data/client/hippo/screens/system-settings.jsx +4 -6
- data/client/hippo/screens/system-settings/mailer-config.jsx +1 -1
- data/client/hippo/screens/system-settings/tenant.jsx +57 -4
- data/client/hippo/screens/user-management.jsx +2 -2
- data/client/hippo/screens/user-management/edit-form.jsx +1 -1
- data/client/hippo/styles/global/fancy-header.scss +2 -1
- data/client/hippo/styles/global/mixins.scss +14 -1
- data/client/hippo/testing/index.js +7 -0
- data/client/hippo/user.js +9 -2
- data/client/hippo/workspace/index.jsx +29 -8
- data/client/hippo/workspace/menu-group.jsx +1 -1
- data/client/hippo/workspace/menu-option.jsx +2 -0
- data/client/hippo/workspace/menu.jsx +30 -6
- data/client/hippo/workspace/screen.jsx +5 -1
- data/client/hippo/workspace/styles.scss +22 -3
- data/command-reference-files/initial/Gemfile +1 -1
- data/config/routes.rb +6 -0
- data/config/screens.rb +9 -17
- data/db/migrate/20171129024737_create_subscriptions.rb +12 -0
- data/fixtures/vcr_cassettes/Tenant_changes/sends_email_when_tenant_identifier_changes.yml +72 -0
- data/fixtures/vcr_cassettes/Tenant_isoloation/disallows_using_a_user_s_token_on_incorrect_domain.yml +141 -0
- data/fixtures/vcr_cassettes/Tenant_isoloation/isolates_bar_s_tenant_data_from_foo.yml +141 -0
- data/fixtures/vcr_cassettes/Tenant_isoloation/isolates_foo_s_tenant_data_from_bar.yml +141 -0
- data/hippo-fw.gemspec +4 -3
- data/lib/hippo.rb +1 -0
- data/lib/hippo/access/roles/basic_user.rb +1 -0
- data/lib/hippo/api/authentication_provider.rb +4 -5
- data/lib/hippo/api/handlers/asset.rb +9 -4
- data/lib/hippo/api/handlers/subscription.rb +39 -0
- data/lib/hippo/api/handlers/user_session.rb +0 -1
- data/lib/hippo/api/helper_methods.rb +8 -4
- data/lib/hippo/api/request_wrapper.rb +12 -1
- data/lib/hippo/command/console.rb +3 -3
- data/lib/hippo/concerns/asset_uploader.rb +8 -2
- data/lib/hippo/concerns/pub_sub.rb +8 -8
- data/lib/hippo/configuration.rb +6 -4
- data/lib/hippo/extension.rb +3 -2
- data/lib/hippo/model.rb +1 -0
- data/lib/hippo/models/subscription.rb +7 -0
- data/lib/hippo/payments.rb +129 -0
- data/lib/hippo/screen.rb +4 -2
- data/lib/hippo/screen/definition.rb +4 -0
- data/lib/hippo/spec_helper.rb +4 -4
- data/lib/hippo/templates/liquid/precision.rb +9 -0
- data/lib/hippo/tenant.rb +4 -5
- data/lib/hippo/user.rb +5 -5
- data/lib/hippo/version.rb +1 -1
- data/lib/hippo/webpack.rb +5 -1
- data/package-lock.json +437 -881
- data/package.json +19 -5
- data/spec/client/components/__snapshots__/query-builder.spec.jsx.snap +34 -1
- data/spec/client/components/__snapshots__/record-finder.spec.jsx.snap +1 -0
- data/spec/client/models/base.spec.js +7 -0
- data/spec/client/models/subscription.spec.js +8 -0
- data/spec/client/screens/__snapshots__/preferences.spec.jsx.snap +223 -0
- data/spec/client/screens/preferences.spec.jsx +10 -0
- data/spec/client/test-models.js +1 -1
- data/spec/client/workspace/__snapshots__/menu.spec.jsx.snap +12 -0
- data/spec/factories/subscription.rb +6 -0
- data/spec/factories/tenant.rb +1 -1
- data/spec/factories/user.rb +1 -1
- data/spec/server/api/tenant_change_spec.rb +11 -8
- data/spec/server/api/tenant_isolation_spec.rb +11 -8
- data/spec/server/api/user_sessions_spec.rb +10 -7
- data/spec/server/api/user_spec.rb +45 -0
- data/spec/server/models/subscription_spec.rb +10 -0
- data/spec/server/payment_helpers.rb +13 -0
- data/spec/server/print/form_spec.rb +1 -1
- data/spec/server/spec_helper.rb +3 -11
- data/templates/js/screen-definitions.js +4 -1
- data/templates/spec/factories/model.rb +1 -1
- data/views/hippo_root_view.erb +5 -5
- metadata +84 -25
- data/client/hippo/components/grid/config.json +0 -3
- data/client/hippo/components/grid/editors.scss +0 -78
- data/client/hippo/components/grid/index.js +0 -2
- data/client/hippo/components/grid/row-editor.scss +0 -74
- data/client/hippo/components/grid/styles.scss +0 -118
- data/client/hippo/components/text-editor/display-modes/Button.jsx +0 -20
- data/client/hippo/components/text-editor/display-modes/ToggleEdit.jsx +0 -23
- data/client/hippo/components/text-editor/display-modes/ToggleInsert.jsx +0 -22
- data/client/hippo/components/text-editor/display-modes/ToggleLayout.jsx +0 -22
- data/client/hippo/components/text-editor/display-modes/TogglePreview.jsx +0 -22
- data/client/hippo/components/text-editor/display-modes/ToggleResize.jsx +0 -22
- data/client/hippo/components/text-editor/display-modes/index.css +0 -0
- data/client/hippo/components/text-editor/display-modes/index.js +0 -30
- data/client/hippo/components/text-editor/image-plugin/Component/Display/index.js +0 -82
- data/client/hippo/components/text-editor/image-plugin/Component/Form/index.js +0 -42
- data/client/hippo/components/text-editor/image-plugin/Component/index.js +0 -16
- data/client/hippo/components/text-editor/image-plugin/Component/index.scss +0 -0
- data/client/hippo/components/text-editor/image-plugin/index.js +0 -32
- data/client/hippo/components/text-editor/image-plugin/index.scss +0 -25
- data/client/hippo/components/toolbar/changes-notification.scss +0 -63
- data/client/hippo/components/toolbar/index.js +0 -3
- data/client/hippo/components/toolbar/styles.scss +0 -74
@@ -1,39 +1,19 @@
|
|
1
|
-
import React from 'react';
|
1
|
+
import React from 'react'; // eslint-disable-line no-unused-vars
|
2
2
|
import PropTypes from 'prop-types';
|
3
|
-
import
|
4
|
-
import { observable, toJS } from 'mobx';
|
5
|
-
import { observer, Provider, PropTypes as MobxPropTypes } from 'mobx-react';
|
6
|
-
import { HTMLRenderer } from 'ory-editor-renderer';
|
3
|
+
import cn from 'classnames';
|
7
4
|
|
8
|
-
import '
|
9
|
-
|
10
|
-
@observer
|
11
|
-
export default class TextEditorRenderer extends React.PureComponent {
|
12
|
-
|
13
|
-
static defaultProps = {
|
14
|
-
assets: observable.array(),
|
15
|
-
}
|
16
|
-
|
17
|
-
static propTypes = {
|
18
|
-
content: PropTypes.object.isRequired,
|
19
|
-
assets: MobxPropTypes.observableArray,
|
20
|
-
}
|
21
|
-
|
22
|
-
static defaultProps = {
|
23
|
-
className: PropTypes.string,
|
24
|
-
}
|
25
|
-
|
26
|
-
render() {
|
27
|
-
return (
|
28
|
-
<Provider
|
29
|
-
assets={this.props.assets}
|
30
|
-
>
|
31
|
-
<HTMLRenderer
|
32
|
-
className={this.props.className} state={toJS(this.props.content)}
|
33
|
-
plugins={plugins}
|
34
|
-
/>
|
35
|
-
</Provider>
|
36
|
-
);
|
37
|
-
}
|
5
|
+
import './renderer.scss';
|
38
6
|
|
7
|
+
export default function TextEditorRenderer({ className, content }) {
|
8
|
+
return (
|
9
|
+
<div
|
10
|
+
className={cn('text-editor-content', className)}
|
11
|
+
dangerouslySetInnerHTML={{ __html: content }}
|
12
|
+
/>
|
13
|
+
);
|
39
14
|
}
|
15
|
+
|
16
|
+
TextEditorRenderer.propTypes = {
|
17
|
+
content: PropTypes.string.isRequired,
|
18
|
+
className: PropTypes.string.isRequired,
|
19
|
+
};
|
@@ -0,0 +1,15 @@
|
|
1
|
+
@import '~ory-editor-core/lib/index.css';
|
2
|
+
|
3
|
+
.grommet .text-editor-content {
|
4
|
+
flex: 1;
|
5
|
+
overflow: auto;
|
6
|
+
-webkit-overflow-scrolling: touch;
|
7
|
+
|
8
|
+
p:not(.grommetux-paragraph) {
|
9
|
+
max-width: inherit;
|
10
|
+
margin-left: 0;
|
11
|
+
margin-top: 0;
|
12
|
+
margin-bottom: 0;
|
13
|
+
}
|
14
|
+
|
15
|
+
}
|
@@ -3,15 +3,13 @@
|
|
3
3
|
.grommet .text-editor {
|
4
4
|
|
5
5
|
flex: 1;
|
6
|
-
display: flex;
|
7
|
-
flex-direction: column;
|
8
6
|
|
9
7
|
.text-editor-content {
|
10
|
-
flex: 1;
|
11
8
|
overflow: auto;
|
9
|
+
-webkit-overflow-scrolling: touch;
|
10
|
+
border: 1px solid #adadad;
|
12
11
|
}
|
13
12
|
|
14
|
-
|
15
13
|
.toolbar > * {
|
16
14
|
display: flex;
|
17
15
|
flex-wrap: wrap;
|
@@ -26,17 +24,6 @@
|
|
26
24
|
margin-bottom: 0;
|
27
25
|
}
|
28
26
|
|
29
|
-
.content-image-wrapper {
|
30
|
-
.image-drop-zone {
|
31
|
-
text-align: center;
|
32
|
-
}
|
33
|
-
.content-image {
|
34
|
-
max-width: 100%;
|
35
|
-
width: auto;
|
36
|
-
height: auto;
|
37
|
-
}
|
38
|
-
}
|
39
|
-
|
40
27
|
button:not(.grommetux-button) {
|
41
28
|
min-width: inherit;
|
42
29
|
padding: 0;
|
@@ -0,0 +1,66 @@
|
|
1
|
+
import FileRepository from '@ckeditor/ckeditor5-upload/src/filerepository';
|
2
|
+
import ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';
|
3
|
+
import mix from '@ckeditor/ckeditor5-utils/src/mix';
|
4
|
+
|
5
|
+
class Adapter {
|
6
|
+
|
7
|
+
constructor(loader, t) {
|
8
|
+
this.loader = loader;
|
9
|
+
this.t = t;
|
10
|
+
}
|
11
|
+
|
12
|
+
get assets() {
|
13
|
+
return this.t.config.get('assets');
|
14
|
+
}
|
15
|
+
|
16
|
+
get asset() {
|
17
|
+
return this.assets.find(
|
18
|
+
asset => asset.metadata && asset.metadata.nodeId === this.loader.id,
|
19
|
+
);
|
20
|
+
}
|
21
|
+
|
22
|
+
upload() {
|
23
|
+
if (!this.asset) {
|
24
|
+
this.assets.push({ metadata: { nodeId: this.loader.id } });
|
25
|
+
if (!this.asset) {
|
26
|
+
return Promise.reject(new Error('unable to create asset model'));
|
27
|
+
}
|
28
|
+
}
|
29
|
+
return new Promise((resolve, reject) => {
|
30
|
+
this.asset.setFile(this.loader.file).then(() => {
|
31
|
+
this.asset.save().then(() => {
|
32
|
+
resolve({ default: this.asset.urlFor() });
|
33
|
+
});
|
34
|
+
}).catch(reject);
|
35
|
+
});
|
36
|
+
}
|
37
|
+
|
38
|
+
}
|
39
|
+
|
40
|
+
|
41
|
+
export default class HippoUploadAdapter {
|
42
|
+
|
43
|
+
static get requires() {
|
44
|
+
return [FileRepository];
|
45
|
+
}
|
46
|
+
|
47
|
+
static get pluginName() {
|
48
|
+
return 'HippoUploadAdapter';
|
49
|
+
}
|
50
|
+
|
51
|
+
constructor(editor) {
|
52
|
+
this.editor = editor;
|
53
|
+
}
|
54
|
+
|
55
|
+
init() {
|
56
|
+
this.editor.plugins.get(FileRepository).createAdapter = loader =>
|
57
|
+
new Adapter(loader, this.editor);
|
58
|
+
}
|
59
|
+
|
60
|
+
destroy() {
|
61
|
+
this.stopListening();
|
62
|
+
}
|
63
|
+
|
64
|
+
}
|
65
|
+
|
66
|
+
mix(Plugin, ObservableMixin);
|
@@ -1,21 +1,16 @@
|
|
1
|
-
import React from 'react';
|
1
|
+
import React from 'react'; // eslint-disable-line no-unused-vars
|
2
2
|
import { Tooltip as Tippy } from 'react-tippy';
|
3
3
|
|
4
4
|
import 'react-tippy/dist/tippy.css';
|
5
5
|
|
6
6
|
// Use a wrapper component even though it doesn't really add any functionality
|
7
7
|
// In the future we'll add a Manager wrapper so that multiple tooltips cannot be shown at once
|
8
|
-
export default
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
{children}
|
17
|
-
</Tippy>
|
18
|
-
);
|
19
|
-
}
|
20
|
-
|
8
|
+
export default function ToolTip({ children, ...tipProps }) {
|
9
|
+
return (
|
10
|
+
<Tippy
|
11
|
+
{...tipProps}
|
12
|
+
>
|
13
|
+
{children}
|
14
|
+
</Tippy>
|
15
|
+
);
|
21
16
|
}
|
@@ -0,0 +1,16 @@
|
|
1
|
+
import React from 'react'; // eslint-disable-line no-unused-vars
|
2
|
+
import Header from 'grommet/components/Header';
|
3
|
+
|
4
|
+
export SaveButton from './save-button';
|
5
|
+
|
6
|
+
export function Toolbar({ children }) {
|
7
|
+
return (
|
8
|
+
<Header
|
9
|
+
className="hippo-toolbar"
|
10
|
+
fixed colorIndex="light-2" align="center"
|
11
|
+
pad={{ horizontal: 'small', vertical: 'small', between: 'small' }}
|
12
|
+
>
|
13
|
+
{children}
|
14
|
+
</Header>
|
15
|
+
);
|
16
|
+
}
|
@@ -5,7 +5,7 @@ import Notification from 'grommet/components/Notification';
|
|
5
5
|
export default function WarningNotification(props) {
|
6
6
|
if (!props.message) { return null; }
|
7
7
|
return (
|
8
|
-
<Notification
|
8
|
+
<Notification size="small" status="warning" {...props} />
|
9
9
|
);
|
10
10
|
}
|
11
11
|
|
@@ -1,4 +1,5 @@
|
|
1
1
|
import { observable, computed } from 'mobx';
|
2
|
+
import { merge } from 'lodash';
|
2
3
|
import { titleize, humanize } from '../lib/util';
|
3
4
|
import Extensions from './index';
|
4
5
|
import RootView from '../workspace/root-view';
|
@@ -7,7 +8,7 @@ export { identifiedBy, identifier } from '../models/base';
|
|
7
8
|
|
8
9
|
export class BaseExtension {
|
9
10
|
|
10
|
-
@observable data;
|
11
|
+
@observable data = {};
|
11
12
|
|
12
13
|
static register() {
|
13
14
|
Extensions.register(this);
|
@@ -18,7 +19,7 @@ export class BaseExtension {
|
|
18
19
|
}
|
19
20
|
|
20
21
|
setBootstrapData(data) {
|
21
|
-
this.data
|
22
|
+
merge(this.data, data);
|
22
23
|
}
|
23
24
|
|
24
25
|
@computed get domain() {
|
@@ -0,0 +1,8 @@
|
|
1
|
+
import './action_cable/connection';
|
2
|
+
import './action_cable/connection_monitor';
|
3
|
+
import './action_cable/consumer';
|
4
|
+
import './action_cable/subscription';
|
5
|
+
import './action_cable/subscriptions';
|
6
|
+
import ActionCable from './action_cable/cable';
|
7
|
+
|
8
|
+
export default ActionCable;
|
@@ -0,0 +1,47 @@
|
|
1
|
+
/* eslint-disable */
|
2
|
+
|
3
|
+
const ActionCable = {
|
4
|
+
|
5
|
+
INTERNAL: {},
|
6
|
+
WebSocket: window.WebSocket,
|
7
|
+
logger: window.console,
|
8
|
+
createConsumer: function(url) {
|
9
|
+
var ref;
|
10
|
+
if (url == null) {
|
11
|
+
url = (ref = this.getConfig("url")) != null ? ref : this.INTERNAL.default_mount_path;
|
12
|
+
}
|
13
|
+
return new ActionCable.Consumer(this.createWebSocketURL(url));
|
14
|
+
},
|
15
|
+
getConfig: function(name) {
|
16
|
+
var element;
|
17
|
+
element = document.head.querySelector(`meta[name='action-cable-${name}']`);
|
18
|
+
return element != null ? element.getAttribute("content") : void 0;
|
19
|
+
},
|
20
|
+
createWebSocketURL: function(url) {
|
21
|
+
var a;
|
22
|
+
if (url && !/^wss?:/i.test(url)) {
|
23
|
+
a = document.createElement("a");
|
24
|
+
a.href = url;
|
25
|
+
// Fix populating Location properties in IE. Otherwise, protocol will be blank.
|
26
|
+
a.href = a.href;
|
27
|
+
a.protocol = a.protocol.replace("http", "ws");
|
28
|
+
return a.href;
|
29
|
+
} else {
|
30
|
+
return url;
|
31
|
+
}
|
32
|
+
},
|
33
|
+
startDebugging: function() {
|
34
|
+
return this.debugging = true;
|
35
|
+
},
|
36
|
+
stopDebugging: function() {
|
37
|
+
return this.debugging = null;
|
38
|
+
},
|
39
|
+
log: function(...messages) {
|
40
|
+
if (this.debugging) {
|
41
|
+
messages.push(Date.now());
|
42
|
+
return this.logger.log("[ActionCable]", ...messages);
|
43
|
+
}
|
44
|
+
}
|
45
|
+
};
|
46
|
+
|
47
|
+
export default ActionCable;
|
@@ -0,0 +1,192 @@
|
|
1
|
+
/* eslint-disable */
|
2
|
+
|
3
|
+
import ActionCable from './cable';
|
4
|
+
|
5
|
+
// Encapsulate the cable connection held by the consumer. This is an internal class not intended for direct user manipulation.
|
6
|
+
var i, message_types, protocols, supportedProtocols, unsupportedProtocol,
|
7
|
+
slice = [].slice,
|
8
|
+
indexOf = [].indexOf;
|
9
|
+
|
10
|
+
protocols = ["actioncable-v1-json", "actioncable-unsupported"];
|
11
|
+
|
12
|
+
//({message_types, protocols} = ActionCable.INTERNAL);
|
13
|
+
message_types = {
|
14
|
+
welcome: "welcome",
|
15
|
+
ping: "ping",
|
16
|
+
confirmation: "confirm_subscription",
|
17
|
+
rejection: "reject_subscription",
|
18
|
+
};
|
19
|
+
|
20
|
+
supportedProtocols = 2 <= protocols.length ? slice.call(protocols, 0, i = protocols.length - 1) : (i = 0, []), unsupportedProtocol = protocols[i++];
|
21
|
+
|
22
|
+
ActionCable.Connection = (function() {
|
23
|
+
class Connection {
|
24
|
+
constructor(consumer) {
|
25
|
+
this.open = this.open.bind(this);
|
26
|
+
this.consumer = consumer;
|
27
|
+
({subscriptions: this.subscriptions} = this.consumer);
|
28
|
+
this.monitor = new ActionCable.ConnectionMonitor(this);
|
29
|
+
this.disconnected = true;
|
30
|
+
}
|
31
|
+
|
32
|
+
send(data) {
|
33
|
+
if (this.isOpen()) {
|
34
|
+
this.webSocket.send(JSON.stringify(data));
|
35
|
+
return true;
|
36
|
+
} else {
|
37
|
+
return false;
|
38
|
+
}
|
39
|
+
}
|
40
|
+
|
41
|
+
open() {
|
42
|
+
if (this.isActive()) {
|
43
|
+
ActionCable.log(`Attempted to open WebSocket, but existing socket is ${this.getState()}`);
|
44
|
+
return false;
|
45
|
+
} else {
|
46
|
+
ActionCable.log(`Opening WebSocket, current state is ${this.getState()}, subprotocols: ${protocols}`);
|
47
|
+
if (this.webSocket != null) {
|
48
|
+
this.uninstallEventHandlers();
|
49
|
+
}
|
50
|
+
this.webSocket = new ActionCable.WebSocket(this.consumer.url, protocols);
|
51
|
+
this.installEventHandlers();
|
52
|
+
this.monitor.start();
|
53
|
+
return true;
|
54
|
+
}
|
55
|
+
}
|
56
|
+
|
57
|
+
close({allowReconnect} = {
|
58
|
+
allowReconnect: true
|
59
|
+
}) {
|
60
|
+
var ref;
|
61
|
+
if (!allowReconnect) {
|
62
|
+
this.monitor.stop();
|
63
|
+
}
|
64
|
+
if (this.isActive()) {
|
65
|
+
return (ref = this.webSocket) != null ? ref.close() : void 0;
|
66
|
+
}
|
67
|
+
}
|
68
|
+
|
69
|
+
reopen() {
|
70
|
+
var error;
|
71
|
+
ActionCable.log(`Reopening WebSocket, current state is ${this.getState()}`);
|
72
|
+
if (this.isActive()) {
|
73
|
+
try {
|
74
|
+
return this.close();
|
75
|
+
} catch (error1) {
|
76
|
+
error = error1;
|
77
|
+
return ActionCable.log("Failed to reopen WebSocket", error);
|
78
|
+
} finally {
|
79
|
+
ActionCable.log(`Reopening WebSocket in ${this.constructor.reopenDelay}ms`);
|
80
|
+
setTimeout(this.open, this.constructor.reopenDelay);
|
81
|
+
}
|
82
|
+
} else {
|
83
|
+
return this.open();
|
84
|
+
}
|
85
|
+
}
|
86
|
+
|
87
|
+
getProtocol() {
|
88
|
+
var ref;
|
89
|
+
return (ref = this.webSocket) != null ? ref.protocol : void 0;
|
90
|
+
}
|
91
|
+
|
92
|
+
isOpen() {
|
93
|
+
return this.isState("open");
|
94
|
+
}
|
95
|
+
|
96
|
+
isActive() {
|
97
|
+
return this.isState("open", "connecting");
|
98
|
+
}
|
99
|
+
|
100
|
+
// Private
|
101
|
+
isProtocolSupported() {
|
102
|
+
var ref;
|
103
|
+
return ref = this.getProtocol(), indexOf.call(supportedProtocols, ref) >= 0;
|
104
|
+
}
|
105
|
+
|
106
|
+
isState(...states) {
|
107
|
+
var ref;
|
108
|
+
return ref = this.getState(), indexOf.call(states, ref) >= 0;
|
109
|
+
}
|
110
|
+
|
111
|
+
getState() {
|
112
|
+
var ref, state, value;
|
113
|
+
for (state in WebSocket) {
|
114
|
+
value = WebSocket[state];
|
115
|
+
if (value === ((ref = this.webSocket) != null ? ref.readyState : void 0)) {
|
116
|
+
return state.toLowerCase();
|
117
|
+
}
|
118
|
+
}
|
119
|
+
return null;
|
120
|
+
}
|
121
|
+
|
122
|
+
installEventHandlers() {
|
123
|
+
var eventName, handler;
|
124
|
+
for (eventName in this.events) {
|
125
|
+
handler = this.events[eventName].bind(this);
|
126
|
+
this.webSocket[`on${eventName}`] = handler;
|
127
|
+
}
|
128
|
+
}
|
129
|
+
|
130
|
+
uninstallEventHandlers() {
|
131
|
+
var eventName;
|
132
|
+
for (eventName in this.events) {
|
133
|
+
this.webSocket[`on${eventName}`] = function() {};
|
134
|
+
}
|
135
|
+
}
|
136
|
+
|
137
|
+
};
|
138
|
+
|
139
|
+
Connection.reopenDelay = 500;
|
140
|
+
|
141
|
+
Connection.prototype.events = {
|
142
|
+
message: function(event) {
|
143
|
+
var identifier, message, type;
|
144
|
+
if (!this.isProtocolSupported()) {
|
145
|
+
return;
|
146
|
+
}
|
147
|
+
|
148
|
+
|
149
|
+
({identifier, message, type} = JSON.parse(event.data));
|
150
|
+
switch (type) {
|
151
|
+
case message_types.welcome:
|
152
|
+
this.monitor.recordConnect();
|
153
|
+
return this.subscriptions.reload();
|
154
|
+
case message_types.ping:
|
155
|
+
return this.monitor.recordPing();
|
156
|
+
case message_types.confirmation:
|
157
|
+
return this.subscriptions.notify(identifier, "connected");
|
158
|
+
case message_types.rejection:
|
159
|
+
return this.subscriptions.reject(identifier);
|
160
|
+
default:
|
161
|
+
return this.subscriptions.notify(identifier, "received", message);
|
162
|
+
}
|
163
|
+
},
|
164
|
+
open: function() {
|
165
|
+
ActionCable.log(`WebSocket onopen event, using '${this.getProtocol()}' subprotocol`);
|
166
|
+
this.disconnected = false;
|
167
|
+
if (!this.isProtocolSupported()) {
|
168
|
+
ActionCable.log("Protocol is unsupported. Stopping monitor and disconnecting.");
|
169
|
+
return this.close({
|
170
|
+
allowReconnect: false
|
171
|
+
});
|
172
|
+
}
|
173
|
+
},
|
174
|
+
close: function(event) {
|
175
|
+
ActionCable.log("WebSocket onclose event");
|
176
|
+
if (this.disconnected) {
|
177
|
+
return;
|
178
|
+
}
|
179
|
+
this.disconnected = true;
|
180
|
+
this.monitor.recordDisconnect();
|
181
|
+
return this.subscriptions.notifyAll("disconnected", {
|
182
|
+
willAttemptReconnect: this.monitor.isRunning()
|
183
|
+
});
|
184
|
+
},
|
185
|
+
error: function() {
|
186
|
+
return ActionCable.log("WebSocket onerror event");
|
187
|
+
}
|
188
|
+
};
|
189
|
+
|
190
|
+
return Connection;
|
191
|
+
|
192
|
+
})();
|