Commit dd03bf30d88eea55564914d1f0503456cb360e5c
1 parent
6091f1a8
Add new React component 'ThingsboardIcon', a form to select an icon from datakey settings
Showing
6 changed files
with
170 additions
and
8 deletions
... | ... | @@ -22,13 +22,17 @@ import ReactSchemaForm from './react/json-form-react.jsx'; |
22 | 22 | import jsonFormTemplate from './json-form.tpl.html'; |
23 | 23 | import { utils } from 'react-schema-form'; |
24 | 24 | |
25 | +import MaterialIconsDialogController from './material-icons-dialog.controller'; | |
26 | +import materialIconsDialogTemplate from './material-icons-dialog.tpl.html'; | |
27 | + | |
25 | 28 | export default angular.module('thingsboard.directives.jsonForm', []) |
26 | 29 | .directive('tbJsonForm', JsonForm) |
30 | + .controller('MaterialIconsDialogController', MaterialIconsDialogController) | |
27 | 31 | .value('ReactSchemaForm', ReactSchemaForm) |
28 | 32 | .name; |
29 | 33 | |
30 | 34 | /*@ngInject*/ |
31 | -function JsonForm($compile, $templateCache, $mdColorPicker) { | |
35 | +function JsonForm($compile, $templateCache, $mdColorPicker, $mdDialog, $document) { | |
32 | 36 | |
33 | 37 | var linker = function (scope, element) { |
34 | 38 | |
... | ... | @@ -90,6 +94,9 @@ function JsonForm($compile, $templateCache, $mdColorPicker) { |
90 | 94 | onColorClick: function(event, key, val) { |
91 | 95 | scope.showColorPicker(event, val); |
92 | 96 | }, |
97 | + onIconClick: function(event) { | |
98 | + scope.openIconDialog(event); | |
99 | + }, | |
93 | 100 | onToggleFullscreen: function() { |
94 | 101 | scope.isFullscreen = !scope.isFullscreen; |
95 | 102 | scope.formProps.isFullscreen = scope.isFullscreen; |
... | ... | @@ -123,6 +130,23 @@ function JsonForm($compile, $templateCache, $mdColorPicker) { |
123 | 130 | }); |
124 | 131 | } |
125 | 132 | |
133 | + scope.openIconDialog = function(event) { | |
134 | + $mdDialog.show({ | |
135 | + controller: 'MaterialIconsDialogController', | |
136 | + controllerAs: 'vm', | |
137 | + templateUrl: materialIconsDialogTemplate, | |
138 | + parent: angular.element($document[0].body), | |
139 | + locals: {icon: scope.icon}, | |
140 | + multiple: true, | |
141 | + fullscreen: true, | |
142 | + targetEvent: event | |
143 | + }).then(function (icon) { | |
144 | + if (event.data && event.data.onValueChanged) { | |
145 | + event.data.onValueChanged(icon); | |
146 | + } | |
147 | + }); | |
148 | + } | |
149 | + | |
126 | 150 | scope.onFullscreenChanged = function() {} |
127 | 151 | |
128 | 152 | scope.validate = function(){ | ... | ... |
... | ... | @@ -131,7 +131,7 @@ class ThingsboardArray extends React.Component { |
131 | 131 | } |
132 | 132 | let forms = this.props.form.items.map(function(form, index){ |
133 | 133 | var copy = this.copyWithIndex(form, i); |
134 | - return this.props.builder(copy, this.props.model, index, this.props.onChange, this.props.onColorClick, this.props.onToggleFullscreen, this.props.mapper, this.props.builder); | |
134 | + return this.props.builder(copy, this.props.model, index, this.props.onChange, this.props.onColorClick, this.props.onIconClick, this.props.onToggleFullscreen, this.props.mapper, this.props.builder); | |
135 | 135 | }.bind(this)); |
136 | 136 | arrays.push( |
137 | 137 | <li key={keys[i]} className="list-group-item"> | ... | ... |
... | ... | @@ -19,7 +19,7 @@ class ThingsboardFieldSet extends React.Component { |
19 | 19 | |
20 | 20 | render() { |
21 | 21 | let forms = this.props.form.items.map(function(form, index){ |
22 | - return this.props.builder(form, this.props.model, index, this.props.onChange, this.props.onColorClick, this.props.onToggleFullscreen, this.props.mapper, this.props.builder); | |
22 | + return this.props.builder(form, this.props.model, index, this.props.onChange, this.props.onColorClick, this.props.onIconClick, this.props.onToggleFullscreen, this.props.mapper, this.props.builder); | |
23 | 23 | }.bind(this)); |
24 | 24 | |
25 | 25 | return ( | ... | ... |
1 | +/* | |
2 | + * Copyright © 2016-2019 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +import $ from 'jquery'; | |
17 | +import React from 'react'; | |
18 | +import ReactDOM from 'react-dom'; | |
19 | +import ThingsboardBaseComponent from './json-form-base-component.jsx'; | |
20 | +import reactCSS from 'reactcss'; | |
21 | +import TextField from 'material-ui/TextField'; | |
22 | +import IconButton from 'material-ui/IconButton'; | |
23 | + | |
24 | +class ThingsboardIcon extends React.Component { | |
25 | + | |
26 | + constructor(props) { | |
27 | + super(props); | |
28 | + this.onValueChanged = this.onValueChanged.bind(this); | |
29 | + this.onIconClick = this.onIconClick.bind(this); | |
30 | + this.onClear = this.onClear.bind(this); | |
31 | + var icon = props.value ? props.value : ''; | |
32 | + this.state = { | |
33 | + icon: icon | |
34 | + }; | |
35 | + } | |
36 | + | |
37 | + componentDidMount() { | |
38 | + var node = ReactDOM.findDOMNode(this); | |
39 | + var iconContainer = $(node).children('#icon-container'); | |
40 | + iconContainer.click(this, function(event) { | |
41 | + event.data.onIconClick(event); | |
42 | + }); | |
43 | + } | |
44 | + | |
45 | + componentWillUnmount () { | |
46 | + var node = ReactDOM.findDOMNode(this); | |
47 | + var iconContainer = $(node).children('#icon-container'); | |
48 | + iconContainer.off( "click" ); | |
49 | + } | |
50 | + | |
51 | + onValueChanged(value) { | |
52 | + var icon = value; | |
53 | + | |
54 | + this.setState({ | |
55 | + icon: value | |
56 | + }) | |
57 | + this.props.onChange(this.props.form.key, value); | |
58 | + } | |
59 | + | |
60 | + onIconClick(event) { | |
61 | + this.props.onIconClick(event); | |
62 | + } | |
63 | + | |
64 | + onClear(event) { | |
65 | + if (event) { | |
66 | + event.stopPropagation(); | |
67 | + } | |
68 | + this.onValueChanged(''); | |
69 | + } | |
70 | + | |
71 | + render() { | |
72 | + | |
73 | + const styles = reactCSS({ | |
74 | + 'default': { | |
75 | + clear: { | |
76 | + marginTop: '15px' | |
77 | + }, | |
78 | + container: { | |
79 | + display: 'flex' | |
80 | + }, | |
81 | + icon: { | |
82 | + display: 'inline-block', | |
83 | + marginRight: '10px', | |
84 | + marginTop: '16px', | |
85 | + marginBottom: 'auto', | |
86 | + cursor: 'pointer', | |
87 | + border: 'solid 1px rgba(0, 0, 0, .27)' | |
88 | + }, | |
89 | + iconContainer: { | |
90 | + display: 'flex', | |
91 | + width: '100%' | |
92 | + }, | |
93 | + iconText: { | |
94 | + display: 'inline-block', | |
95 | + width: '100%' | |
96 | + }, | |
97 | + }, | |
98 | + }); | |
99 | + | |
100 | + var fieldClass = "tb-field"; | |
101 | + if (this.props.form.required) { | |
102 | + fieldClass += " tb-required"; | |
103 | + } | |
104 | + if (this.state.focused) { | |
105 | + fieldClass += " tb-focused"; | |
106 | + } | |
107 | + | |
108 | + var pickedIcon = 'more_horiz'; | |
109 | + if (this.state.icon != '') { | |
110 | + pickedIcon = this.state.icon; | |
111 | + } | |
112 | + | |
113 | + return ( | |
114 | + <div style={ styles.container }> | |
115 | + <div id="icon-container" style={ styles.iconContainer }> | |
116 | + <IconButton iconClassName="material-icons" style={ styles.icon }> | |
117 | + {pickedIcon} | |
118 | + </IconButton> | |
119 | + <TextField | |
120 | + className={fieldClass} | |
121 | + floatingLabelText={this.props.form.title} | |
122 | + hintText={this.props.form.placeholder} | |
123 | + errorText={this.props.error} | |
124 | + value={this.state.icon} | |
125 | + disabled={this.props.form.readonly} | |
126 | + style={ styles.iconText } /> | |
127 | + </div> | |
128 | + <IconButton iconClassName="material-icons" tooltip="Clear" onTouchTap={this.onClear}>clear</IconButton> | |
129 | + </div> | |
130 | + ); | |
131 | + } | |
132 | +} | |
133 | + | |
134 | +export default ThingsboardBaseComponent(ThingsboardIcon); | ... | ... |
... | ... | @@ -32,6 +32,7 @@ import ThingsboardImage from './json-form-image.jsx'; |
32 | 32 | import ThingsboardCheckbox from './json-form-checkbox.jsx'; |
33 | 33 | import Help from 'react-schema-form/lib/Help'; |
34 | 34 | import ThingsboardFieldSet from './json-form-fieldset.jsx'; |
35 | +import ThingsboardIcon from './json-form-icon.jsx'; | |
35 | 36 | |
36 | 37 | import _ from 'lodash'; |
37 | 38 | |
... | ... | @@ -58,11 +59,13 @@ class ThingsboardSchemaForm extends React.Component { |
58 | 59 | 'css': ThingsboardCss, |
59 | 60 | 'color': ThingsboardColor, |
60 | 61 | 'rc-select': ThingsboardRcSelect, |
61 | - 'fieldset': ThingsboardFieldSet | |
62 | + 'fieldset': ThingsboardFieldSet, | |
63 | + 'icon': ThingsboardIcon | |
62 | 64 | }; |
63 | 65 | |
64 | 66 | this.onChange = this.onChange.bind(this); |
65 | 67 | this.onColorClick = this.onColorClick.bind(this); |
68 | + this.onIconClick = this.onIconClick.bind(this); | |
66 | 69 | this.onToggleFullscreen = this.onToggleFullscreen.bind(this); |
67 | 70 | this.hasConditions = false; |
68 | 71 | } |
... | ... | @@ -84,7 +87,7 @@ class ThingsboardSchemaForm extends React.Component { |
84 | 87 | } |
85 | 88 | |
86 | 89 | |
87 | - builder(form, model, index, onChange, onColorClick, onToggleFullscreen, mapper) { | |
90 | + builder(form, model, index, onChange, onColorClick, onIconClick, onToggleFullscreen, mapper) { | |
88 | 91 | var type = form.type; |
89 | 92 | let Field = this.mapper[type]; |
90 | 93 | if(!Field) { |
... | ... | @@ -97,7 +100,7 @@ class ThingsboardSchemaForm extends React.Component { |
97 | 100 | return null; |
98 | 101 | } |
99 | 102 | } |
100 | - return <Field model={model} form={form} key={index} onChange={onChange} onColorClick={onColorClick} onToggleFullscreen={onToggleFullscreen} mapper={mapper} builder={this.builder}/> | |
103 | + return <Field model={model} form={form} key={index} onChange={onChange} onColorClick={onColorClick} onIconClick={onIconClick} onToggleFullscreen={onToggleFullscreen} mapper={mapper} builder={this.builder}/> | |
101 | 104 | } |
102 | 105 | |
103 | 106 | createSchema(theForm) { |
... | ... | @@ -107,7 +110,7 @@ class ThingsboardSchemaForm extends React.Component { |
107 | 110 | mapper = _.merge(this.mapper, this.props.mapper); |
108 | 111 | } |
109 | 112 | let forms = merged.map(function(form, index) { |
110 | - return this.builder(form, this.props.model, index, this.onChange, this.onColorClick, this.onToggleFullscreen, mapper); | |
113 | + return this.builder(form, this.props.model, index, this.onChange, this.onColorClick, this.onIconClick, this.onToggleFullscreen, mapper); | |
111 | 114 | }.bind(this)); |
112 | 115 | |
113 | 116 | let formClass = 'SchemaForm'; |
... | ... | @@ -158,4 +161,4 @@ class ThingsboardSchemaGroup extends React.Component{ |
158 | 161 | <div style={{padding: '20px'}} className={this.state.showGroup?"":"invisible"}>{this.props.forms}</div> |
159 | 162 | </section>); |
160 | 163 | } |
161 | -} | |
\ No newline at end of file | ||
164 | +} | ... | ... |