senangwebs-aframe-editor 1.6.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/.babelrc +3 -0
  2. package/.editorconfig +12 -0
  3. package/.eslintignore +2 -0
  4. package/.eslintrc +40 -0
  5. package/.github/workflows/ci.yml +39 -0
  6. package/.husky/pre-commit +4 -0
  7. package/.prettierignore +1 -0
  8. package/.prettierrc.json +5 -0
  9. package/.stylelintrc +12 -0
  10. package/LICENSE +21 -0
  11. package/README.md +75 -0
  12. package/assets/gltf.svg +49 -0
  13. package/dist/aframe-inspector.js +106250 -0
  14. package/dist/aframe-inspector.js.map +1 -0
  15. package/dist/aframe-inspector.min.js +29040 -0
  16. package/dist/aframe-inspector.min.js.LICENSE.txt +56 -0
  17. package/dist/aframe-inspector.min.js.map +1 -0
  18. package/examples/360video.html +48 -0
  19. package/examples/colors.html +18 -0
  20. package/examples/controllers.html +60 -0
  21. package/examples/embedded-zoom.html +78 -0
  22. package/examples/embedded.html +79 -0
  23. package/examples/empty.html +13 -0
  24. package/examples/index-aframe.html +66 -0
  25. package/examples/index.html +71 -0
  26. package/examples/supercraft.html +6 -0
  27. package/index.html +8 -0
  28. package/package.json +84 -0
  29. package/senangwebs-webverse-editor.png +0 -0
  30. package/src/components/AwesomeIcon.js +53 -0
  31. package/src/components/Collapsible.js +57 -0
  32. package/src/components/EntityRepresentation.js +83 -0
  33. package/src/components/Main.js +222 -0
  34. package/src/components/__tests__/Collapsible.test.js +30 -0
  35. package/src/components/components/AddComponent.js +104 -0
  36. package/src/components/components/CommonComponents.js +160 -0
  37. package/src/components/components/Component.js +151 -0
  38. package/src/components/components/ComponentsContainer.js +52 -0
  39. package/src/components/components/DefaultComponents.js +1 -0
  40. package/src/components/components/Mixins.js +83 -0
  41. package/src/components/components/PropertyRow.js +145 -0
  42. package/src/components/components/Sidebar.js +51 -0
  43. package/src/components/icons/BackViewIcon.js +27 -0
  44. package/src/components/icons/BottomViewIcon.js +26 -0
  45. package/src/components/icons/FrontViewIcon.js +23 -0
  46. package/src/components/icons/LeftViewIcon.js +24 -0
  47. package/src/components/icons/PerspectiveIcon.js +23 -0
  48. package/src/components/icons/PrimitiveBoxIcon.js +143 -0
  49. package/src/components/icons/PrimitiveConeIcon.js +44 -0
  50. package/src/components/icons/PrimitiveCylinderIcon.js +51 -0
  51. package/src/components/icons/PrimitiveEmptyEntityIcon.js +78 -0
  52. package/src/components/icons/PrimitiveImageIcon.js +86 -0
  53. package/src/components/icons/PrimitiveLightIcon.js +107 -0
  54. package/src/components/icons/PrimitivePlaneIcon.js +87 -0
  55. package/src/components/icons/PrimitiveSphereIcon.js +39 -0
  56. package/src/components/icons/PrimitiveTextIcon.js +89 -0
  57. package/src/components/icons/PrimitiveTorusIcon.js +31 -0
  58. package/src/components/icons/RightViewIcon.js +24 -0
  59. package/src/components/icons/TopViewIcon.js +24 -0
  60. package/src/components/modals/Modal.js +107 -0
  61. package/src/components/modals/ModalHelp.js +97 -0
  62. package/src/components/modals/ModalPrimitive.js +114 -0
  63. package/src/components/modals/ModalTextures.js +430 -0
  64. package/src/components/scenegraph/Entity.js +142 -0
  65. package/src/components/scenegraph/SceneGraph.js +337 -0
  66. package/src/components/scenegraph/Toolbar.js +147 -0
  67. package/src/components/viewport/CameraToolbar.js +122 -0
  68. package/src/components/viewport/TransformToolbar.js +102 -0
  69. package/src/components/viewport/ViewportHUD.js +33 -0
  70. package/src/components/widgets/BooleanWidget.js +49 -0
  71. package/src/components/widgets/ColorWidget.js +89 -0
  72. package/src/components/widgets/InputWidget.js +42 -0
  73. package/src/components/widgets/NumberWidget.js +179 -0
  74. package/src/components/widgets/SelectWidget.js +58 -0
  75. package/src/components/widgets/TextureWidget.js +252 -0
  76. package/src/components/widgets/Vec2Widget.js +55 -0
  77. package/src/components/widgets/Vec3Widget.js +58 -0
  78. package/src/components/widgets/Vec4Widget.js +61 -0
  79. package/src/components/widgets/index.js +9 -0
  80. package/src/index.js +301 -0
  81. package/src/lib/EditorControls.js +336 -0
  82. package/src/lib/Events.js +6 -0
  83. package/src/lib/TransformControls.js +1365 -0
  84. package/src/lib/assetsLoader.js +43 -0
  85. package/src/lib/assetsUtils.js +30 -0
  86. package/src/lib/cameras.js +121 -0
  87. package/src/lib/entity.js +556 -0
  88. package/src/lib/history.js +30 -0
  89. package/src/lib/raycaster.js +129 -0
  90. package/src/lib/shortcuts.js +211 -0
  91. package/src/lib/utils.js +118 -0
  92. package/src/lib/viewport.js +268 -0
  93. package/src/style/components.styl +275 -0
  94. package/src/style/entity.styl +22 -0
  95. package/src/style/help.styl +40 -0
  96. package/src/style/index.styl +358 -0
  97. package/src/style/lib.styl +41 -0
  98. package/src/style/primitiveModal.styl +90 -0
  99. package/src/style/scenegraph.styl +173 -0
  100. package/src/style/select.styl +71 -0
  101. package/src/style/textureModal.styl +220 -0
  102. package/src/style/viewport.styl +168 -0
  103. package/src/style/widgets.styl +71 -0
  104. package/webpack.config.js +65 -0
@@ -0,0 +1,33 @@
1
+ import React from 'react';
2
+ import EntityRepresentation from '../EntityRepresentation';
3
+ import Events from '../../lib/Events';
4
+
5
+ export default class ViewportHUD extends React.Component {
6
+ constructor(props) {
7
+ super(props);
8
+ this.state = {
9
+ hoveredEntity: null,
10
+ selectedEntity: null
11
+ };
12
+ }
13
+
14
+ componentDidMount() {
15
+ Events.on('raycastermouseenter', (el) => {
16
+ this.setState({ hoveredEntity: el });
17
+ });
18
+
19
+ Events.on('raycastermouseleave', (el) => {
20
+ this.setState({ hoveredEntity: el });
21
+ });
22
+ }
23
+
24
+ render() {
25
+ return (
26
+ <div id="viewportHud">
27
+ <p>
28
+ <EntityRepresentation entity={this.state.hoveredEntity} />
29
+ </p>
30
+ </div>
31
+ );
32
+ }
33
+ }
@@ -0,0 +1,49 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+
4
+ export default class BooleanWidget extends React.Component {
5
+ static propTypes = {
6
+ componentname: PropTypes.string.isRequired,
7
+ entity: PropTypes.object,
8
+ name: PropTypes.string.isRequired,
9
+ onChange: PropTypes.func,
10
+ value: PropTypes.bool
11
+ };
12
+
13
+ static defaultProps = {
14
+ value: false
15
+ };
16
+
17
+ constructor(props) {
18
+ super(props);
19
+ this.state = { value: this.props.value };
20
+ }
21
+
22
+ componentDidUpdate(prevProps) {
23
+ if (this.props.value !== prevProps.value) {
24
+ this.setState({ value: this.props.value });
25
+ }
26
+ }
27
+
28
+ onChange = (e) => {
29
+ var value = e.target.checked;
30
+ this.setState({ value: value });
31
+ if (this.props.onChange) {
32
+ this.props.onChange(this.props.name, value);
33
+ }
34
+ };
35
+
36
+ render() {
37
+ var id = this.props.componentname + '.' + this.props.name;
38
+
39
+ return (
40
+ <input
41
+ id={id}
42
+ type="checkbox"
43
+ checked={this.state.value}
44
+ value={this.state.value}
45
+ onChange={this.onChange}
46
+ />
47
+ );
48
+ }
49
+ }
@@ -0,0 +1,89 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+
4
+ export default class ColorWidget extends React.Component {
5
+ static propTypes = {
6
+ componentname: PropTypes.string.isRequired,
7
+ entity: PropTypes.object,
8
+ name: PropTypes.string.isRequired,
9
+ onChange: PropTypes.func,
10
+ value: PropTypes.string
11
+ };
12
+
13
+ static defaultProps = {
14
+ value: '#ffffff'
15
+ };
16
+
17
+ constructor(props) {
18
+ super(props);
19
+
20
+ var value = this.props.value;
21
+ this.color = new THREE.Color();
22
+
23
+ this.state = {
24
+ value: value,
25
+ pickerValue: this.getHexString(value)
26
+ };
27
+ }
28
+
29
+ setValue(value) {
30
+ var pickerValue = this.getHexString(value);
31
+
32
+ this.setState({
33
+ value: value,
34
+ pickerValue: pickerValue
35
+ });
36
+
37
+ if (this.props.onChange) {
38
+ this.props.onChange(this.props.name, value);
39
+ }
40
+ }
41
+
42
+ componentDidUpdate(prevProps) {
43
+ if (this.props.value !== prevProps.value) {
44
+ this.setState({
45
+ value: this.props.value,
46
+ pickerValue: this.getHexString(this.props.value)
47
+ });
48
+ }
49
+ }
50
+
51
+ getHexString(value) {
52
+ return '#' + this.color.set(value).getHexString();
53
+ }
54
+
55
+ onChange = (e) => {
56
+ this.setValue(e.target.value);
57
+ };
58
+
59
+ onKeyUp = (e) => {
60
+ e.stopPropagation();
61
+ // if (e.keyCode === 13)
62
+ this.setValue(e.target.value);
63
+ };
64
+
65
+ onChangeText = (e) => {
66
+ this.setState({ value: e.target.value });
67
+ };
68
+
69
+ render() {
70
+ return (
71
+ <span className="color-widget">
72
+ <input
73
+ type="color"
74
+ className="color"
75
+ value={this.state.pickerValue}
76
+ title={this.state.value}
77
+ onChange={this.onChange}
78
+ />
79
+ <input
80
+ type="text"
81
+ className="color_value"
82
+ value={this.state.value}
83
+ onKeyUp={this.onKeyUp}
84
+ onChange={this.onChangeText}
85
+ />
86
+ </span>
87
+ );
88
+ }
89
+ }
@@ -0,0 +1,42 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+
4
+ export default class InputWidget extends React.Component {
5
+ static propTypes = {
6
+ componentname: PropTypes.string,
7
+ entity: PropTypes.object,
8
+ name: PropTypes.string.isRequired,
9
+ onChange: PropTypes.func,
10
+ value: PropTypes.any
11
+ };
12
+
13
+ constructor(props) {
14
+ super(props);
15
+ this.state = { value: this.props.value || '' };
16
+ }
17
+
18
+ onChange = (e) => {
19
+ var value = e.target.value;
20
+ this.setState({ value: value });
21
+ if (this.props.onChange) {
22
+ this.props.onChange(this.props.name, value);
23
+ }
24
+ };
25
+
26
+ componentDidUpdate(prevProps) {
27
+ if (this.props.value !== prevProps.value) {
28
+ this.setState({ value: this.props.value });
29
+ }
30
+ }
31
+
32
+ render() {
33
+ return (
34
+ <input
35
+ type="text"
36
+ className="string"
37
+ value={this.state.value || ''}
38
+ onChange={this.onChange}
39
+ />
40
+ );
41
+ }
42
+ }
@@ -0,0 +1,179 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+
4
+ export default class NumberWidget extends React.Component {
5
+ static propTypes = {
6
+ componentname: PropTypes.string,
7
+ entity: PropTypes.object,
8
+ max: PropTypes.number,
9
+ min: PropTypes.number,
10
+ name: PropTypes.string,
11
+ onChange: PropTypes.func,
12
+ precision: PropTypes.number,
13
+ step: PropTypes.number,
14
+ value: PropTypes.number
15
+ };
16
+
17
+ static defaultProps = {
18
+ min: -Infinity,
19
+ max: Infinity,
20
+ value: 0,
21
+ precision: 3,
22
+ step: 1
23
+ };
24
+
25
+ constructor(props) {
26
+ super(props);
27
+ this.state = {
28
+ value: this.props.value,
29
+ displayValue:
30
+ typeof this.props.value === 'number'
31
+ ? this.props.value.toFixed(this.props.precision)
32
+ : ''
33
+ };
34
+ this.input = React.createRef();
35
+ }
36
+
37
+ componentDidMount() {
38
+ this.distance = 0;
39
+ this.onMouseDownValue = 0;
40
+ this.prevPointer = [0, 0];
41
+
42
+ this.setValue(this.props.value);
43
+ this.onBlur();
44
+ }
45
+
46
+ onMouseMove = (event) => {
47
+ const currentValue = parseFloat(this.state.value);
48
+ const pointer = [event.clientX, event.clientY];
49
+ const delta =
50
+ pointer[0] - this.prevPointer[0] - (pointer[1] - this.prevPointer[1]);
51
+ this.distance += delta;
52
+
53
+ // Add minimum tolerance to reduce unintentional drags when clicking on input.
54
+ // if (Math.abs(delta) <= 2) { return; }
55
+
56
+ let value =
57
+ this.onMouseDownValue +
58
+ ((this.distance / (event.shiftKey ? 5 : 50)) * this.props.step) / 2;
59
+ value = Math.min(this.props.max, Math.max(this.props.min, value));
60
+ if (currentValue !== value) {
61
+ this.setValue(value);
62
+ }
63
+ this.prevPointer = [event.clientX, event.clientY];
64
+ };
65
+
66
+ onMouseDown = (event) => {
67
+ event.preventDefault();
68
+ this.distance = 0;
69
+ this.onMouseDownValue = this.state.value;
70
+ this.prevPointer = [event.clientX, event.clientY];
71
+ document.addEventListener('mousemove', this.onMouseMove, false);
72
+ document.addEventListener('mouseup', this.onMouseUp, false);
73
+ };
74
+
75
+ onMouseUp = () => {
76
+ document.removeEventListener('mousemove', this.onMouseMove, false);
77
+ document.removeEventListener('mouseup', this.onMouseUp, false);
78
+
79
+ if (Math.abs(this.distance) < 2) {
80
+ this.input.current.focus();
81
+ this.input.current.select();
82
+ }
83
+ };
84
+
85
+ setValue(value) {
86
+ if (value === this.state.value) return;
87
+
88
+ if (value !== undefined) {
89
+ if (this.props.precision === 0) {
90
+ value = parseInt(value);
91
+ } else {
92
+ value = parseFloat(value);
93
+ }
94
+
95
+ // If we inadvertently typed a character in the field, set value to the previous value from props
96
+ if (isNaN(value)) {
97
+ value = this.props.value;
98
+ }
99
+
100
+ if (value < this.props.min) {
101
+ value = this.props.min;
102
+ }
103
+ if (value > this.props.max) {
104
+ value = this.props.max;
105
+ }
106
+
107
+ this.setState({
108
+ value: value,
109
+ displayValue: value.toFixed(this.props.precision)
110
+ });
111
+
112
+ if (this.props.onChange) {
113
+ this.props.onChange(this.props.name, parseFloat(value.toFixed(5)));
114
+ }
115
+ }
116
+ }
117
+
118
+ componentDidUpdate(prevProps) {
119
+ // This will be triggered typically when the element is changed directly with
120
+ // element.setAttribute.
121
+
122
+ // We use Object.is instead of === for comparison here so that comparing two NaN doesn't trigger an infinite update.
123
+ // Object.is(NaN, NaN) is true, NaN === NaN is false
124
+ if (!Object.is(this.props.value, prevProps.value)) {
125
+ this.setState({
126
+ value: this.props.value,
127
+ displayValue: this.props.value.toFixed(this.props.precision)
128
+ });
129
+ }
130
+ }
131
+
132
+ onBlur = () => {
133
+ this.setValue(parseFloat(this.input.current.value));
134
+ this.setState({ class: '' });
135
+ };
136
+
137
+ onChange = (e) => {
138
+ this.setState({ value: e.target.value, displayValue: e.target.value });
139
+ };
140
+
141
+ onKeyDown = (event) => {
142
+ event.stopPropagation();
143
+
144
+ // enter.
145
+ if (event.keyCode === 13) {
146
+ this.setValue(parseFloat(this.input.current.value));
147
+ this.input.current.blur();
148
+ return;
149
+ }
150
+
151
+ // up.
152
+ if (event.keyCode === 38) {
153
+ this.setValue(parseFloat(this.state.value) + 0.01);
154
+ return;
155
+ }
156
+
157
+ // down.
158
+ if (event.keyCode === 40) {
159
+ this.setValue(parseFloat(this.state.value) - 0.01);
160
+ return;
161
+ }
162
+ };
163
+
164
+ render() {
165
+ return (
166
+ <input
167
+ ref={this.input}
168
+ className="number"
169
+ type="text"
170
+ value={this.state.displayValue}
171
+ onKeyDown={this.onKeyDown}
172
+ onChange={this.onChange}
173
+ onMouseDown={this.onMouseDown}
174
+ onFocus={this.onFocus}
175
+ onBlur={this.onBlur}
176
+ />
177
+ );
178
+ }
179
+ }
@@ -0,0 +1,58 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import Select from 'react-select';
4
+
5
+ export default class SelectWidget extends React.Component {
6
+ static propTypes = {
7
+ componentname: PropTypes.string.isRequired,
8
+ entity: PropTypes.object,
9
+ name: PropTypes.string.isRequired,
10
+ onChange: PropTypes.func,
11
+ options: PropTypes.array.isRequired,
12
+ value: PropTypes.string
13
+ };
14
+
15
+ constructor(props) {
16
+ super(props);
17
+ const value = this.props.value || '';
18
+ this.state = { value: { value: value, label: value } };
19
+ }
20
+
21
+ onChange = (value) => {
22
+ this.setState({ value: value }, () => {
23
+ if (this.props.onChange) {
24
+ this.props.onChange(this.props.name, value.value);
25
+ }
26
+ });
27
+ };
28
+
29
+ componentDidUpdate(prevProps) {
30
+ const props = this.props;
31
+ if (props.value !== prevProps.value) {
32
+ this.setState({
33
+ value: { value: props.value, label: props.value }
34
+ });
35
+ }
36
+ }
37
+
38
+ render() {
39
+ const options = this.props.options.map((value) => {
40
+ return { value: value, label: value };
41
+ });
42
+
43
+ return (
44
+ <Select
45
+ className="select-widget"
46
+ classNamePrefix="select"
47
+ options={options}
48
+ simpleValue
49
+ clearable={true}
50
+ placeholder=""
51
+ value={this.state.value}
52
+ noResultsText="No value found"
53
+ onChange={this.onChange}
54
+ searchable={true}
55
+ />
56
+ );
57
+ }
58
+ }
@@ -0,0 +1,252 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import Events from '../../lib/Events';
4
+
5
+ function getUrlFromId(assetId) {
6
+ return (
7
+ assetId.length > 1 &&
8
+ document.querySelector(assetId) &&
9
+ document.querySelector(assetId).getAttribute('src')
10
+ );
11
+ }
12
+
13
+ function GetFilename(url) {
14
+ if (url) {
15
+ var m = url.toString().match(/.*\/(.+?)\./);
16
+ if (m && m.length > 1) {
17
+ return m[1];
18
+ }
19
+ }
20
+ return '';
21
+ }
22
+
23
+ function insertNewAsset(type, id, src) {
24
+ var element = null;
25
+ switch (type) {
26
+ case 'img':
27
+ {
28
+ element = document.createElement('img');
29
+ element.id = id;
30
+ element.src = src;
31
+ }
32
+ break;
33
+ }
34
+ if (element) {
35
+ document.getElementsByTagName('a-assets')[0].appendChild(element);
36
+ }
37
+ }
38
+
39
+ function insertOrGetImageAsset(src) {
40
+ var id = GetFilename(src);
41
+ // Search for already loaded asset by src
42
+ var element = document.querySelector("a-assets > img[src='" + src + "']");
43
+
44
+ if (element) {
45
+ id = element.id;
46
+ } else {
47
+ // Check if first char of the ID is a number (Non a valid ID)
48
+ // In that case a 'i' preffix will be added
49
+ if (!isNaN(parseInt(id[0], 10))) {
50
+ id = 'i' + id;
51
+ }
52
+ if (document.getElementById(id)) {
53
+ var i = 1;
54
+ while (document.getElementById(id + '_' + i)) {
55
+ i++;
56
+ }
57
+ id += '_' + i;
58
+ }
59
+ insertNewAsset('img', id, src);
60
+ }
61
+
62
+ return id;
63
+ }
64
+
65
+ export default class TextureWidget extends React.Component {
66
+ static propTypes = {
67
+ componentname: PropTypes.string,
68
+ entity: PropTypes.object,
69
+ mapName: PropTypes.string,
70
+ name: PropTypes.string.isRequired,
71
+ onChange: PropTypes.func,
72
+ value: PropTypes.oneOfType([PropTypes.object, PropTypes.string])
73
+ };
74
+
75
+ static defaultProps = {
76
+ value: '',
77
+ mapName: 'nomap',
78
+ dataURL: ''
79
+ };
80
+
81
+ constructor(props) {
82
+ super(props);
83
+ this.state = { value: this.props.value || '' };
84
+ this.canvas = React.createRef();
85
+ }
86
+
87
+ componentDidMount() {
88
+ this.setValue(this.props.value || '');
89
+ }
90
+
91
+ componentDidUpdate(prevProps) {
92
+ var component = this.props.entity.components[this.props.componentname];
93
+ if (!component) {
94
+ return;
95
+ }
96
+ // component.attrValue may be undefined if component is from a mixin
97
+ var newValue = component.attrValue && component.attrValue[this.props.name];
98
+
99
+ // This will be triggered typically when the element is changed directly with element.setAttribute
100
+ // Compare with prevProps.value instead of this.state.value to avoid infinite loops
101
+ if (newValue && newValue !== prevProps.value) {
102
+ this.setValue(newValue);
103
+ }
104
+ }
105
+
106
+ setValue(value) {
107
+ var canvas = this.canvas.current;
108
+ var context = canvas.getContext('2d');
109
+
110
+ function paintPreviewWithImage(image) {
111
+ var filename = image.src.replace(/^.*[\\/]/, '');
112
+ if (image !== undefined && image.width > 0) {
113
+ canvas.title = filename;
114
+ var scale = canvas.width / image.width;
115
+ context.drawImage(
116
+ image,
117
+ 0,
118
+ 0,
119
+ image.width * scale,
120
+ image.height * scale
121
+ );
122
+ // self.setState({dataURL: canvas.toDataURL()});
123
+ } else {
124
+ context.clearRect(0, 0, canvas.width, canvas.height);
125
+ }
126
+ }
127
+
128
+ function paintPreview(texture) {
129
+ var image = texture.image;
130
+ paintPreviewWithImage(image);
131
+ }
132
+
133
+ function getTextureFromSrc(src) {
134
+ for (var hash in AFRAME.INSPECTOR.sceneEl.systems.material.textureCache) {
135
+ // The key in textureCache is not always a json.
136
+ // For example <a-videosphere src="#video"> gives a "video" key in textureCache.
137
+ // So we check for '{' before using JSON.parse here.
138
+ if (hash[0] === '{' && JSON.parse(hash).src === src) {
139
+ return AFRAME.INSPECTOR.sceneEl.systems.material.textureCache[hash];
140
+ }
141
+ }
142
+ return null;
143
+ }
144
+
145
+ var url;
146
+ var isAssetHash = value[0] === '#';
147
+ var isAssetImg = value instanceof HTMLImageElement;
148
+ var isAssetVideo = value instanceof HTMLVideoElement;
149
+ var isAssetImgOrVideo = isAssetImg || isAssetVideo;
150
+
151
+ if (isAssetImgOrVideo) {
152
+ url = value.src;
153
+ } else if (isAssetHash) {
154
+ url = getUrlFromId(value);
155
+ } else {
156
+ url = AFRAME.utils.srcLoader.parseUrl(value);
157
+ }
158
+
159
+ var texture = getTextureFromSrc(value);
160
+ var valueType = null;
161
+ valueType = isAssetImgOrVideo || isAssetHash ? 'asset' : 'url';
162
+ if (!isAssetVideo && texture) {
163
+ texture.then(paintPreview);
164
+ } else if (!isAssetVideo && url) {
165
+ // The image still didn't load
166
+ var image = new Image();
167
+ image.addEventListener(
168
+ 'load',
169
+ () => {
170
+ paintPreviewWithImage(image);
171
+ },
172
+ false
173
+ );
174
+ image.src = url;
175
+ } else {
176
+ context.clearRect(0, 0, canvas.width, canvas.height);
177
+ }
178
+
179
+ this.setState({
180
+ value: isAssetImgOrVideo ? '#' + value.id : value,
181
+ valueType: valueType,
182
+ url: url
183
+ });
184
+ }
185
+
186
+ notifyChanged = (value) => {
187
+ if (this.props.onChange) {
188
+ this.props.onChange(this.props.name, value);
189
+ }
190
+ this.setState({ value: value });
191
+ };
192
+
193
+ onChange = (e) => {
194
+ var value = e.target.value;
195
+ this.setState({ value: value });
196
+ this.notifyChanged(value);
197
+ };
198
+
199
+ removeMap = () => {
200
+ this.setValue('');
201
+ this.notifyChanged('');
202
+ };
203
+
204
+ openDialog = () => {
205
+ Events.emit('opentexturesmodal', this.state.value, (image) => {
206
+ if (!image) {
207
+ return;
208
+ }
209
+ var value = image.value;
210
+ if (image.type !== 'asset') {
211
+ var assetId = insertOrGetImageAsset(image.src);
212
+ value = '#' + assetId;
213
+ }
214
+
215
+ if (this.props.onChange) {
216
+ this.props.onChange(this.props.name, value);
217
+ }
218
+
219
+ this.setValue(value);
220
+ });
221
+ };
222
+
223
+ render() {
224
+ let hint = '';
225
+ if (this.state.value) {
226
+ if (this.state.valueType === 'asset') {
227
+ hint = 'Asset ID: ' + this.state.value + '\nURL: ' + this.state.url;
228
+ } else {
229
+ hint = 'URL: ' + this.state.value;
230
+ }
231
+ }
232
+
233
+ return (
234
+ <span className="texture">
235
+ <input
236
+ className="map_value string"
237
+ type="text"
238
+ title={hint}
239
+ value={this.state.value}
240
+ onChange={this.onChange}
241
+ />
242
+ <canvas
243
+ ref={this.canvas}
244
+ width="32"
245
+ height="16"
246
+ title={hint}
247
+ onClick={this.openDialog}
248
+ />
249
+ </span>
250
+ );
251
+ }
252
+ }