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
@@ -0,0 +1,64 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import FieldWrapper from 'grommet/components/FormField';
|
3
|
+
import PaymentFields from 'payment-fields';
|
4
|
+
import { action, observable } from 'mobx';
|
5
|
+
import { observer } from 'mobx-react';
|
6
|
+
import { getColumnProps } from 'react-flexbox-grid';
|
7
|
+
import classnames from 'classnames';
|
8
|
+
import './field.scss';
|
9
|
+
|
10
|
+
@observer
|
11
|
+
export default class PaymentField extends React.Component {
|
12
|
+
|
13
|
+
@action.bound
|
14
|
+
onFocus() {
|
15
|
+
this.wrapper._onFocus();
|
16
|
+
this.errorMessage = '';
|
17
|
+
}
|
18
|
+
|
19
|
+
@action.bound
|
20
|
+
onBlur({ isValid, isPotentiallyValid }) {
|
21
|
+
this.isValid = isValid;
|
22
|
+
this.wrapper._onBlur();
|
23
|
+
this.errorMessage = isPotentiallyValid ? '' : this.props.errorMessage;
|
24
|
+
}
|
25
|
+
|
26
|
+
@observable isValid = false;
|
27
|
+
@observable errorMessage = '';
|
28
|
+
|
29
|
+
@action.bound onValidityChange({ isValid, isPotentiallyValid }) {
|
30
|
+
this.isValid = isValid;
|
31
|
+
this.errorMessage = isPotentiallyValid ? '' : this.props.errorMessage;
|
32
|
+
}
|
33
|
+
|
34
|
+
exposeError() {
|
35
|
+
if (!this.isValid) {
|
36
|
+
this.errorMessage = this.props.errorMessage;
|
37
|
+
}
|
38
|
+
}
|
39
|
+
|
40
|
+
@action.bound
|
41
|
+
setRef(f) { this.wrapper = f; }
|
42
|
+
|
43
|
+
render() {
|
44
|
+
const {
|
45
|
+
label, className, ...cardFieldProps
|
46
|
+
} = getColumnProps(this.props);
|
47
|
+
return (
|
48
|
+
<div className={classnames('payment-field form-field', className)}>
|
49
|
+
<FieldWrapper
|
50
|
+
error={this.errorMessage}
|
51
|
+
label={label}
|
52
|
+
ref={this.setRef}
|
53
|
+
>
|
54
|
+
<PaymentFields.Field
|
55
|
+
{...cardFieldProps}
|
56
|
+
onFocus={this.onFocus}
|
57
|
+
onBlur={this.onBlur}
|
58
|
+
/>
|
59
|
+
</FieldWrapper>
|
60
|
+
</div>
|
61
|
+
);
|
62
|
+
}
|
63
|
+
|
64
|
+
}
|
@@ -0,0 +1,18 @@
|
|
1
|
+
.form-field.payment-field {
|
2
|
+
padding-bottom: 0;
|
3
|
+
.grommetux-form-field {
|
4
|
+
padding-bottom: 0;
|
5
|
+
}
|
6
|
+
.grommetux-form-field__contents {
|
7
|
+
height: 40px;
|
8
|
+
overflow: hidden;
|
9
|
+
padding-left: 22px;
|
10
|
+
}
|
11
|
+
.hosted-card-field {
|
12
|
+
height: 100%;
|
13
|
+
border: 0;
|
14
|
+
}
|
15
|
+
.payment-field {
|
16
|
+
height: 40px;
|
17
|
+
}
|
18
|
+
}
|
@@ -8,7 +8,7 @@ import ReactDOM from 'react-dom';
|
|
8
8
|
import { isFunction, invoke, defaults, map, uniqueId } from 'lodash';
|
9
9
|
import { autobind } from 'core-decorators';
|
10
10
|
|
11
|
-
export default class PopoutWindow extends React.
|
11
|
+
export default class PopoutWindow extends React.Component {
|
12
12
|
|
13
13
|
static propTypes = {
|
14
14
|
title: PropTypes.string.isRequired,
|
@@ -7,7 +7,7 @@ import Clause from './query-builder/clause';
|
|
7
7
|
import './query-builder/query-builder.scss';
|
8
8
|
|
9
9
|
@observer
|
10
|
-
export default class QueryBuilder extends React.
|
10
|
+
export default class QueryBuilder extends React.Component {
|
11
11
|
|
12
12
|
static defaultProps = {
|
13
13
|
autoFetch: false,
|
@@ -5,7 +5,7 @@ import { observer } from 'mobx-react';
|
|
5
5
|
import { action } from 'mobx';
|
6
6
|
|
7
7
|
@observer
|
8
|
-
export default class BooleanPicker extends React.
|
8
|
+
export default class BooleanPicker extends React.Component {
|
9
9
|
|
10
10
|
@action.bound onChange(ev) {
|
11
11
|
this.props.clause.value = ev.target.checked;
|
@@ -9,7 +9,7 @@ import ClauseModel from '../../models/query/clause';
|
|
9
9
|
|
10
10
|
|
11
11
|
@observer
|
12
|
-
export class Radio extends React.
|
12
|
+
export class Radio extends React.Component {
|
13
13
|
|
14
14
|
static propTypes = {
|
15
15
|
name: PropTypes.string.isRequired,
|
@@ -40,7 +40,7 @@ export class Radio extends React.PureComponent {
|
|
40
40
|
}
|
41
41
|
|
42
42
|
@observer
|
43
|
-
export class ClauseFilter extends React.
|
43
|
+
export class ClauseFilter extends React.Component {
|
44
44
|
|
45
45
|
static propTypes = {
|
46
46
|
clause: PropTypes.instanceOf(ClauseModel).isRequired,
|
@@ -3,9 +3,11 @@ import { defaults } from 'lodash';
|
|
3
3
|
import PropTypes from 'prop-types';
|
4
4
|
import { observer } from 'mobx-react';
|
5
5
|
import { action } from 'mobx';
|
6
|
+
import Button from 'grommet/components/Button';
|
6
7
|
import Box from 'grommet/components/Box';
|
7
8
|
import Menu from 'grommet/components/Menu';
|
8
9
|
import TextInput from 'grommet/components/TextInput';
|
10
|
+
import RefreshIcon from 'grommet/components/icons/base/Refresh';
|
9
11
|
import ClauseModel from '../../models/query/clause';
|
10
12
|
import { Radio, ClauseFilter } from './clause-filter';
|
11
13
|
import BooleanPicker from './boolean-picker';
|
@@ -17,7 +19,7 @@ const defaultHandlers = {
|
|
17
19
|
};
|
18
20
|
|
19
21
|
@observer
|
20
|
-
export default class Clause extends React.
|
22
|
+
export default class Clause extends React.Component {
|
21
23
|
|
22
24
|
static defaultProps = {
|
23
25
|
typeHandlers: {},
|
@@ -28,28 +30,28 @@ export default class Clause extends React.PureComponent {
|
|
28
30
|
typeHandlers: PropTypes.object,
|
29
31
|
}
|
30
32
|
|
31
|
-
@action.bound
|
32
|
-
onSelect() {
|
33
|
+
@action.bound onSelect() {
|
33
34
|
this.menuRef._onClose();
|
34
35
|
}
|
35
36
|
|
36
|
-
@action.bound
|
37
|
-
onValueChange(ev) {
|
37
|
+
@action.bound onValueChange(ev) {
|
38
38
|
this.props.clause.value = ev.target.value;
|
39
39
|
}
|
40
40
|
|
41
|
-
@action.bound
|
42
|
-
setMenuRef(ref) {
|
41
|
+
@action.bound setMenuRef(ref) {
|
43
42
|
this.menuRef = ref;
|
44
43
|
}
|
45
44
|
|
45
|
+
@action.bound onRefresh() {
|
46
|
+
this.props.clause.query.fetch();
|
47
|
+
}
|
48
|
+
|
46
49
|
get handlers() {
|
47
50
|
return defaults(this.props.typeHandlers, defaultHandlers);
|
48
51
|
}
|
49
52
|
|
50
53
|
renderInputTag() {
|
51
|
-
const Tag = this.handlers[this.props.clause.field.
|
52
|
-
|
54
|
+
const Tag = this.handlers[this.props.clause.field.queryType];
|
53
55
|
if (Tag) {
|
54
56
|
return <Tag clause={this.props.clause} />;
|
55
57
|
}
|
@@ -67,7 +69,7 @@ export default class Clause extends React.PureComponent {
|
|
67
69
|
const { props: { clause } } = this;
|
68
70
|
|
69
71
|
return (
|
70
|
-
<Box className="clause" direction='row' pad={{ between: 'small' }} align="center">
|
72
|
+
<Box responsive={false} className="clause" direction='row' pad={{ between: 'small' }} align="center">
|
71
73
|
<Menu
|
72
74
|
ref={this.setMenuRef}
|
73
75
|
size='large'
|
@@ -91,6 +93,10 @@ export default class Clause extends React.PureComponent {
|
|
91
93
|
</Box>
|
92
94
|
</Menu>
|
93
95
|
{this.renderInputTag()}
|
96
|
+
<Button
|
97
|
+
icon={<RefreshIcon />}
|
98
|
+
onClick={this.onRefresh}
|
99
|
+
/>
|
94
100
|
</Box>
|
95
101
|
);
|
96
102
|
}
|
@@ -4,7 +4,7 @@ import { action } from 'mobx';
|
|
4
4
|
import DateTime from '../date-time';
|
5
5
|
|
6
6
|
@observer
|
7
|
-
export default class DatePicker extends React.
|
7
|
+
export default class DatePicker extends React.Component {
|
8
8
|
|
9
9
|
@action.bound onChange({ target: { value: dates } }) {
|
10
10
|
this.props.clause.value = `${dates[0].toISOString()}...${dates[1].toISOString()}`;
|
@@ -1,7 +1,28 @@
|
|
1
1
|
.query-builder {
|
2
2
|
.clause {
|
3
|
-
:
|
4
|
-
|
3
|
+
input { flex: 1; }
|
4
|
+
.reload {
|
5
|
+
padding: 0;
|
6
|
+
}
|
7
|
+
.reload {
|
8
|
+
display: none;
|
9
|
+
}
|
10
|
+
&:last-child .reload {
|
11
|
+
display: inline-block;
|
12
|
+
}
|
13
|
+
.grommetux-button > span {
|
14
|
+
padding: 0;
|
15
|
+
}
|
16
|
+
.grommetux-menu button {
|
17
|
+
max-width: 40vw;
|
18
|
+
text-overflow: ellipsis;
|
19
|
+
overflow: hidden;
|
20
|
+
}
|
21
|
+
input {
|
22
|
+
// set a min width so the input won't overflow flexbox
|
23
|
+
min-width: 40px;
|
5
24
|
}
|
6
25
|
}
|
26
|
+
|
27
|
+
|
7
28
|
}
|
@@ -8,17 +8,18 @@ import { Field } from 'hippo/components/form';
|
|
8
8
|
|
9
9
|
import Button from 'grommet/components/Button';
|
10
10
|
import SearchIcon from 'grommet/components/icons/base/Search';
|
11
|
-
|
11
|
+
import { BaseModel } from '../models/base';
|
12
12
|
import Query from '../models/query';
|
13
13
|
import './record-finder/record-finder.scss';
|
14
14
|
import QueryLayer from './record-finder/query-layer';
|
15
15
|
|
16
16
|
@inject('formState')
|
17
17
|
@observer
|
18
|
-
export default class RecordFinder extends React.
|
18
|
+
export default class RecordFinder extends React.Component {
|
19
19
|
|
20
20
|
static propTypes = {
|
21
21
|
query: PropTypes.instanceOf(Query).isRequired,
|
22
|
+
model: PropTypes.instanceOf(BaseModel),
|
22
23
|
name: PropTypes.string.isRequired,
|
23
24
|
label: PropTypes.string,
|
24
25
|
recordsTitle: PropTypes.string.isRequired,
|
@@ -66,6 +67,7 @@ export default class RecordFinder extends React.PureComponent {
|
|
66
67
|
query,
|
67
68
|
onRecordFound: _,
|
68
69
|
recordsTitle,
|
70
|
+
model,
|
69
71
|
...otherProps
|
70
72
|
} = this.props;
|
71
73
|
|
@@ -73,6 +75,7 @@ export default class RecordFinder extends React.PureComponent {
|
|
73
75
|
<Field
|
74
76
|
className='record-finder'
|
75
77
|
onKeyPress={this.onKeyPress}
|
78
|
+
readOnly={Boolean(model && !model.isNew)}
|
76
79
|
{...otherProps}
|
77
80
|
>
|
78
81
|
<QueryLayer
|
@@ -15,7 +15,7 @@ import DataTable from '../data-table';
|
|
15
15
|
import QueryBuilder from '../query-builder';
|
16
16
|
|
17
17
|
@observer
|
18
|
-
export default class QueryLayer extends React.
|
18
|
+
export default class QueryLayer extends React.Component {
|
19
19
|
|
20
20
|
static propTypes = {
|
21
21
|
title: PropTypes.string.isRequired,
|
@@ -25,7 +25,7 @@ export default class Screen extends React.Component {
|
|
25
25
|
<div
|
26
26
|
data-screen-id={this.props.screen.definition.id}
|
27
27
|
className={classnames(
|
28
|
-
'screen',
|
28
|
+
'hippo-screen',
|
29
29
|
this.props.screen.definition.id,
|
30
30
|
this.props.className, {
|
31
31
|
'is-active': this.props.screen.isActive,
|
@@ -1,29 +1,29 @@
|
|
1
1
|
import React from 'react';
|
2
2
|
import PropTypes from 'prop-types';
|
3
|
-
import { action, observable
|
4
|
-
import { isEmpty } from 'lodash';
|
3
|
+
import { action, observable } from 'mobx';
|
5
4
|
import { observer, Provider, PropTypes as MobxPropTypes } from 'mobx-react';
|
6
5
|
|
7
|
-
|
8
|
-
import
|
6
|
+
import BalloonEditor from '@ckeditor/ckeditor5-editor-balloon/src/ballooneditor';
|
7
|
+
import EssentialsPlugin from '@ckeditor/ckeditor5-essentials/src/essentials';
|
8
|
+
import AutoformatPlugin from '@ckeditor/ckeditor5-autoformat/src/autoformat';
|
9
|
+
import BoldPlugin from '@ckeditor/ckeditor5-basic-styles/src/bold';
|
10
|
+
import ItalicPlugin from '@ckeditor/ckeditor5-basic-styles/src/italic';
|
11
|
+
import BlockquotePlugin from '@ckeditor/ckeditor5-block-quote/src/blockquote';
|
12
|
+
import HeadingPlugin from '@ckeditor/ckeditor5-heading/src/heading';
|
13
|
+
import ImagePlugin from '@ckeditor/ckeditor5-image/src/image';
|
14
|
+
import ImagecaptionPlugin from '@ckeditor/ckeditor5-image/src/imagecaption';
|
15
|
+
import ImagestylePlugin from '@ckeditor/ckeditor5-image/src/imagestyle';
|
16
|
+
import ImagetoolbarPlugin from '@ckeditor/ckeditor5-image/src/imagetoolbar';
|
17
|
+
import LinkPlugin from '@ckeditor/ckeditor5-link/src/link';
|
18
|
+
import ListPlugin from '@ckeditor/ckeditor5-list/src/list';
|
19
|
+
import ParagraphPlugin from '@ckeditor/ckeditor5-paragraph/src/paragraph';
|
20
|
+
import ImageuploadPlugin from '@ckeditor/ckeditor5-upload/src/imageupload';
|
9
21
|
|
10
|
-
|
11
|
-
import { Trash, Toolbar } from 'ory-editor-ui';
|
12
|
-
import 'ory-editor-ui/lib/index.css';
|
13
|
-
import 'ory-editor-core/lib/index.css';
|
14
|
-
|
15
|
-
import { plugins, defaultPlugin } from './text-editor/plugins';
|
16
|
-
import DisplayModeToggle from './text-editor/display-modes';
|
22
|
+
import HippoUploadAdapter from './text-editor/upload-adapter';
|
17
23
|
import './text-editor/text-editor.scss';
|
18
24
|
|
19
|
-
const editorInstance = new Editor({
|
20
|
-
plugins,
|
21
|
-
editables: [createEmptyState()],
|
22
|
-
defaultPlugin,
|
23
|
-
});
|
24
|
-
|
25
25
|
@observer
|
26
|
-
export default class TextEditor extends React.
|
26
|
+
export default class TextEditor extends React.Component {
|
27
27
|
|
28
28
|
static defaultProps = {
|
29
29
|
assets: observable.array(),
|
@@ -31,16 +31,73 @@ export default class TextEditor extends React.PureComponent {
|
|
31
31
|
|
32
32
|
static propTypes = {
|
33
33
|
defaultContent: PropTypes.object,
|
34
|
-
|
34
|
+
onReady: PropTypes.func.isRequired,
|
35
35
|
assets: MobxPropTypes.observableArray,
|
36
36
|
}
|
37
37
|
|
38
|
-
|
39
|
-
|
40
|
-
this.
|
41
|
-
|
38
|
+
@action.bound setRef(r) {
|
39
|
+
this.body = r;
|
40
|
+
BalloonEditor.create(this.body, {
|
41
|
+
plugins: [
|
42
|
+
EssentialsPlugin,
|
43
|
+
AutoformatPlugin,
|
44
|
+
BoldPlugin,
|
45
|
+
ItalicPlugin,
|
46
|
+
BlockquotePlugin,
|
47
|
+
HeadingPlugin,
|
48
|
+
ImagePlugin,
|
49
|
+
ImagecaptionPlugin,
|
50
|
+
ImagestylePlugin,
|
51
|
+
ImagetoolbarPlugin,
|
52
|
+
LinkPlugin,
|
53
|
+
ListPlugin,
|
54
|
+
ParagraphPlugin,
|
55
|
+
ImageuploadPlugin,
|
56
|
+
HippoUploadAdapter,
|
57
|
+
],
|
58
|
+
assets: this.props.assets,
|
59
|
+
toolbar: {
|
60
|
+
items: [
|
61
|
+
'headings',
|
62
|
+
'bold',
|
63
|
+
'italic',
|
64
|
+
'link',
|
65
|
+
'bulletedList',
|
66
|
+
'numberedList',
|
67
|
+
'blockQuote',
|
68
|
+
'undo',
|
69
|
+
'redo',
|
70
|
+
],
|
71
|
+
},
|
72
|
+
image: {
|
73
|
+
toolbar: [
|
74
|
+
'imageTextAlternative', '|',
|
75
|
+
'imageStyleAlignLeft', 'imageStyleFull', 'imageStyleAlignRight',
|
76
|
+
],
|
77
|
+
styles: [
|
78
|
+
// This option is equal to a situation where no style is applied.
|
79
|
+
'imageStyleFull',
|
80
|
+
|
81
|
+
// This represents an image aligned to left.
|
82
|
+
'imageStyleAlignLeft',
|
83
|
+
|
84
|
+
// This represents an image aligned to right.
|
85
|
+
'imageStyleAlignRight',
|
86
|
+
],
|
87
|
+
},
|
88
|
+
}).then((e) => {
|
89
|
+
this.editor = e;
|
90
|
+
this.props.onReady(this);
|
91
|
+
});
|
92
|
+
}
|
93
|
+
|
94
|
+
get contents() {
|
95
|
+
return this.editor.getData();
|
42
96
|
}
|
43
97
|
|
98
|
+
set contents(html) {
|
99
|
+
this.editor.setData(html);
|
100
|
+
}
|
44
101
|
|
45
102
|
@action.bound
|
46
103
|
onEditStateChange(state) {
|
@@ -53,23 +110,8 @@ export default class TextEditor extends React.PureComponent {
|
|
53
110
|
<Provider
|
54
111
|
assets={this.props.assets}
|
55
112
|
>
|
56
|
-
|
57
|
-
|
58
|
-
editor={editorInstance}
|
59
|
-
onSave={this.onSave}
|
60
|
-
>
|
61
|
-
{this.props.children}
|
62
|
-
</DisplayModeToggle>
|
63
|
-
<div className="text-editor-content">
|
64
|
-
<Editable
|
65
|
-
editor={editorInstance}
|
66
|
-
id={this.content.id}
|
67
|
-
onAddImage={this.props.onAddImage}
|
68
|
-
onChange={this.onEditStateChange}
|
69
|
-
/>
|
70
|
-
</div>
|
71
|
-
<Trash editor={editorInstance}/>
|
72
|
-
<Toolbar editor={editorInstance} />
|
113
|
+
|
114
|
+
<div className="text-editor" ref={this.setRef}>
|
73
115
|
</div>
|
74
116
|
|
75
117
|
</Provider>
|