@@ -74,6 +74,8 @@ class StructEditor extends Component {
74
74
constructor ( props ) {
75
75
super ( props ) ;
76
76
this . state = {
77
+ hasError : false ,
78
+ errorMessage : '' ,
77
79
enableCursor : false ,
78
80
clientX : 0 ,
79
81
clientY : 0 ,
@@ -148,117 +150,149 @@ class StructEditor extends Component {
148
150
}
149
151
150
152
componentDidMount ( ) {
151
- this . editor = new Editor ( this . editorRef . current , {
152
- ...this . props . options ,
153
- } ) ;
154
- const ketcher = ketcherProvider . getKetcher ( ) ;
155
- if ( ketcher ?. editor . macromoleculeConvertionError ) {
156
- this . props . onShowMacromoleculesErrorMessage (
157
- ketcher . editor . macromoleculeConvertionError ,
158
- ) ;
159
- ketcher . editor . clearMacromoleculeConvertionError ( ) ;
160
- }
161
- setupEditor ( this . editor , this . props ) ;
162
- if ( this . props . onInit ) this . props . onInit ( this . editor ) ;
163
-
164
- this . editor . event . message . add ( ( msg ) => {
165
- const el = this . logRef . current ;
166
- if ( msg . info && this . props . showAttachmentPoints ) {
167
- try {
168
- const parsedInfo = JSON . parse ( msg . info ) ;
169
- el . innerHTML = `Atom Id: ${ parsedInfo . atomid } , Bond Id: ${ parsedInfo . bondid } ` ;
170
- } catch ( e ) {
171
- KetcherLogger . error (
172
- 'StructEditor.jsx::StructEditor::componentDidMount' ,
173
- e ,
174
- ) ;
175
- el . innerHTML = msg . info ;
176
- }
177
- el . classList . add ( classes . visible ) ;
178
- } else {
179
- el . classList . remove ( classes . visible ) ;
153
+ try {
154
+ this . editor = new Editor ( this . editorRef . current , {
155
+ ...this . props . options ,
156
+ } ) ;
157
+ const ketcher = ketcherProvider . getKetcher ( ) ;
158
+ if ( ketcher ?. editor . macromoleculeConvertionError ) {
159
+ this . props . onShowMacromoleculesErrorMessage (
160
+ ketcher . editor . macromoleculeConvertionError ,
161
+ ) ;
162
+ ketcher . editor . clearMacromoleculeConvertionError ( ) ;
180
163
}
181
- } ) ;
182
-
183
- this . editor . event . cursor . add ( ( csr ) => {
184
- let clientX , clientY ;
185
-
186
- switch ( csr . status ) {
187
- case 'enable' : {
188
- this . editorRef . current . classList . add ( classes . enableCursor ) ;
189
- const { left, top, right, bottom } =
190
- this . editorRef . current . getBoundingClientRect ( ) ;
191
-
192
- clientX = csr . cursorPosition . clientX ;
193
- clientY = csr . cursorPosition . clientY ;
194
-
195
- const handShouldBeShown =
196
- clientX >= left &&
197
- clientX <= right &&
198
- clientY >= top &&
199
- clientX <= bottom ;
200
- if ( ! this . state . enableCursor && handShouldBeShown ) {
164
+ setupEditor ( this . editor , this . props ) ;
165
+ if ( this . props . onInit ) this . props . onInit ( this . editor ) ;
166
+
167
+ this . editor . event . message . add ( ( msg ) => {
168
+ const el = this . logRef . current ;
169
+ if ( msg . info && this . props . showAttachmentPoints ) {
170
+ try {
171
+ const parsedInfo = JSON . parse ( msg . info ) ;
172
+ el . innerHTML = `Atom Id: ${ parsedInfo . atomid } , Bond Id: ${ parsedInfo . bondid } ` ;
173
+ } catch ( e ) {
174
+ KetcherLogger . error (
175
+ 'StructEditor.jsx::StructEditor::componentDidMount' ,
176
+ e ,
177
+ ) ;
178
+ el . innerHTML = msg . info ;
179
+ }
180
+ el . classList . add ( classes . visible ) ;
181
+ } else {
182
+ el . classList . remove ( classes . visible ) ;
183
+ }
184
+ } ) ;
185
+
186
+ this . editor . event . cursor . add ( ( csr ) => {
187
+ let clientX , clientY ;
188
+
189
+ switch ( csr . status ) {
190
+ case 'enable' : {
191
+ this . editorRef . current . classList . add ( classes . enableCursor ) ;
192
+ const { left, top, right, bottom } =
193
+ this . editorRef . current . getBoundingClientRect ( ) ;
194
+
195
+ clientX = csr . cursorPosition . clientX ;
196
+ clientY = csr . cursorPosition . clientY ;
197
+
198
+ const handShouldBeShown =
199
+ clientX >= left &&
200
+ clientX <= right &&
201
+ clientY >= top &&
202
+ clientX <= bottom ;
203
+ if ( ! this . state . enableCursor && handShouldBeShown ) {
204
+ this . setState ( {
205
+ enableCursor : true ,
206
+ } ) ;
207
+ }
208
+ break ;
209
+ }
210
+
211
+ case 'move' : {
212
+ this . editorRef . current . classList . add ( classes . enableCursor ) ;
201
213
this . setState ( {
202
214
enableCursor : true ,
215
+ clientX,
216
+ clientY,
203
217
} ) ;
218
+ break ;
204
219
}
205
- break ;
206
- }
207
220
208
- case 'move' : {
209
- this . editorRef . current . classList . add ( classes . enableCursor ) ;
210
- this . setState ( {
211
- enableCursor : true ,
212
- clientX,
213
- clientY,
214
- } ) ;
215
- break ;
216
- }
221
+ case 'disable' : {
222
+ this . editorRef . current . classList . remove ( classes . enableCursor ) ;
223
+ this . setState ( {
224
+ enableCursor : false ,
225
+ } ) ;
226
+ break ;
227
+ }
217
228
218
- case 'disable ' : {
219
- this . editorRef . current . classList . remove ( classes . enableCursor ) ;
220
- this . setState ( {
221
- enableCursor : false ,
222
- } ) ;
223
- break ;
224
- }
229
+ case 'leave ' : {
230
+ this . editorRef . current . classList . remove ( classes . enableCursor ) ;
231
+ this . setState ( {
232
+ enableCursor : false ,
233
+ } ) ;
234
+ break ;
235
+ }
225
236
226
- case 'leave ' : {
227
- this . editorRef . current . classList . remove ( classes . enableCursor ) ;
228
- this . setState ( {
229
- enableCursor : false ,
230
- } ) ;
231
- break ;
232
- }
237
+ case 'mouseover ' : {
238
+ this . editorRef . current . classList . add ( classes . enableCursor ) ;
239
+ this . setState ( {
240
+ enableCursor : true ,
241
+ } ) ;
242
+ break ;
243
+ }
233
244
234
- case 'mouseover' : {
235
- this . editorRef . current . classList . add ( classes . enableCursor ) ;
236
- this . setState ( {
237
- enableCursor : true ,
238
- } ) ;
239
- break ;
245
+ default :
246
+ break ;
240
247
}
248
+ } ) ;
241
249
242
- default :
243
- break ;
244
- }
245
- } ) ;
246
-
247
- this . editor . event . message . dispatch ( {
248
- info : JSON . stringify ( this . props . toolOpts ) ,
249
- } ) ;
250
+ this . editor . event . message . dispatch ( {
251
+ info : JSON . stringify ( this . props . toolOpts ) ,
252
+ } ) ;
250
253
251
- this . editorRef . current . addEventListener ( 'wheel' , this . handleWheel ) ;
252
- this . editor . render . observeCanvasResize ( ) ;
254
+ this . editorRef . current . addEventListener ( 'wheel' , this . handleWheel ) ;
255
+ this . editor . render . observeCanvasResize ( ) ;
256
+ window . addEventListener ( 'error' , this . globalErrorHandler ) ;
257
+ } catch ( error ) {
258
+ this . setState ( { hasError : true , errorMessage : error . message } ) ;
259
+ }
253
260
}
254
261
255
262
componentWillUnmount ( ) {
256
263
removeEditorHandlers ( this . editor , this . props ) ;
257
264
this . editorRef . current . removeEventListener ( 'wheel' , this . handleWheel ) ;
258
265
this . editor . render . unobserveCanvasResize ( ) ;
266
+ window . removeEventListener ( 'error' , this . globalErrorHandler ) ;
259
267
}
260
268
269
+ globalErrorHandler = ( errorEvent ) => {
270
+ const error = errorEvent . error ;
271
+ const message =
272
+ error && error . message
273
+ ? 'An error occurred: ' + error . message
274
+ : 'Something went wrong. The error is on our side. Please try again later.' ;
275
+ this . setState ( { hasError : true , errorMessage : message } ) ;
276
+ } ;
277
+
278
+ handleDismiss = ( ) => {
279
+ this . setState ( { hasError : false , errorMessage : '' } ) ;
280
+ const cliparea = document . querySelector ( '.cliparea' ) ;
281
+ if ( cliparea ) {
282
+ cliparea . focus ( ) ;
283
+ }
284
+ } ;
285
+
261
286
render ( ) {
287
+ if ( this . state . hasError ) {
288
+ return (
289
+ < InfoModal
290
+ message = { this . state . errorMessage }
291
+ close = { this . handleDismiss }
292
+ />
293
+ ) ;
294
+ }
295
+
262
296
const {
263
297
Tag = 'div' ,
264
298
className,
0 commit comments