1- import React from 'react' ;
1+ import React , { Component } from 'react' ;
22import PropTypes from 'prop-types' ;
33import { Form , FormGroup , FormLabel } from 'react-bootstrap' ;
44import AceEditor from 'react-ace' ;
@@ -9,56 +9,107 @@ import { UserUIDataContext } from '../../../helpers/contexts.js';
99// load the ACE editor only when rendering in the browser
1010import { getAceModeFromExtension } from '../../helpers/syntaxHighlighting.js' ;
1111
12- const SourceCodeField = ( {
13- input,
14- mode,
15- meta : { error, warning } ,
16- label = null ,
17- children,
18- tabIndex,
19- onBlur,
20- readOnly = false ,
21- ...props
22- } ) => (
23- < FormGroup controlId = { input . name } className = "mb-3" >
24- { Boolean ( label ) && (
25- < FormLabel className = { error ? 'text-danger' : warning ? 'text-warning' : undefined } > { label } </ FormLabel >
26- ) }
27- { canUseDOM && (
28- < div className = { readOnly ? 'noselection' : '' } >
29- < UserUIDataContext . Consumer >
30- { ( { vimMode = false , darkTheme = true , editorFontSize = 16 } ) => (
31- < AceEditor
32- { ...props }
33- { ...input }
34- mode = { getAceModeFromExtension ( mode ) }
35- theme = { darkTheme ? 'monokai' : 'github' }
36- name = { input . name }
37- tabIndex = { tabIndex }
38- keyboardHandler = { vimMode ? 'vim' : undefined }
39- width = "100%"
40- height = "100%"
41- minLines = { 5 }
42- maxLines = { 20 }
43- readOnly = { readOnly }
44- fontSize = { editorFontSize }
45- onBlur = {
46- ( ) => input . onBlur ( ) // this is a hack that will ensure blur call without distorting the contents
47- }
48- editorProps = { {
49- $blockScrolling : Infinity ,
50- $autoScrollEditorIntoView : false ,
51- } }
52- />
53- ) }
54- </ UserUIDataContext . Consumer >
55- </ div >
56- ) }
57- { error && < Form . Text className = "text-danger" > { error } </ Form . Text > }
58- { ! error && warning && < Form . Text className = "text-warning" > { warning } </ Form . Text > }
59- { children }
60- </ FormGroup >
61- ) ;
12+ const editorProps = {
13+ $blockScrolling : Infinity ,
14+ $autoScrollEditorIntoView : false ,
15+ } ;
16+ const digitCodes = { } ;
17+ for ( let i = 0 ; i <= 9 ; ++ i ) {
18+ digitCodes [ 'Digit' + i ] = i ;
19+ digitCodes [ 'Numpad' + i ] = i ;
20+ }
21+
22+ class SourceCodeField extends Component {
23+ constructor ( ) {
24+ super ( ) ;
25+ this . focusedEditor = null ;
26+ }
27+
28+ keyDownEventHandler = ev => {
29+ const { readOnly = false , getSnippet = null , setSnippet = null } = this . props ;
30+
31+ if (
32+ this . focusedEditor &&
33+ ! readOnly &&
34+ ! ev . repeat &&
35+ ! ev . shiftKey &&
36+ ev . ctrlKey &&
37+ digitCodes [ ev . code ] !== undefined
38+ ) {
39+ if ( ev . altKey ) {
40+ const text = this . focusedEditor . getSelectedText ( ) || this . focusedEditor . getValue ( ) ;
41+ if ( text ) {
42+ setSnippet ( digitCodes [ ev . code ] , text ) ;
43+ }
44+ } else {
45+ const snippet = getSnippet ( digitCodes [ ev . code ] ) ;
46+ if ( snippet ) {
47+ this . focusedEditor . insert ( snippet ) ;
48+ }
49+ }
50+ ev . stopPropagation ( ) ;
51+ }
52+ } ;
53+
54+ focusHandler = ( _ , editor ) => {
55+ this . focusedEditor = editor ;
56+ } ;
57+
58+ blurHandler = ( ) => {
59+ this . props . input . onBlur ( ) ; // this is a hack that will ensure blur call without distorting the contents
60+ this . focusedEditor = null ;
61+ } ;
62+
63+ render ( ) {
64+ const {
65+ input,
66+ mode,
67+ meta : { error, warning } ,
68+ label = null ,
69+ children,
70+ tabIndex,
71+ onBlur,
72+ readOnly = false ,
73+ ...props
74+ } = this . props ;
75+ return (
76+ < FormGroup controlId = { input . name } className = "mb-3" >
77+ { Boolean ( label ) && (
78+ < FormLabel className = { error ? 'text-danger' : warning ? 'text-warning' : undefined } > { label } </ FormLabel >
79+ ) }
80+ { canUseDOM && (
81+ < div className = { readOnly ? 'noselection' : '' } onKeyDownCapture = { this . keyDownEventHandler } >
82+ < UserUIDataContext . Consumer >
83+ { ( { vimMode = false , darkTheme = true , editorFontSize = 16 } ) => (
84+ < AceEditor
85+ { ...props }
86+ { ...input }
87+ mode = { getAceModeFromExtension ( mode ) }
88+ theme = { darkTheme ? 'monokai' : 'github' }
89+ name = { input . name }
90+ tabIndex = { tabIndex }
91+ keyboardHandler = { vimMode ? 'vim' : undefined }
92+ width = "100%"
93+ height = "100%"
94+ minLines = { 5 }
95+ maxLines = { 20 }
96+ readOnly = { readOnly }
97+ fontSize = { editorFontSize }
98+ onBlur = { this . blurHandler }
99+ editorProps = { editorProps }
100+ onFocus = { this . focusHandler }
101+ />
102+ ) }
103+ </ UserUIDataContext . Consumer >
104+ </ div >
105+ ) }
106+ { error && < Form . Text className = "text-danger" > { error } </ Form . Text > }
107+ { ! error && warning && < Form . Text className = "text-warning" > { warning } </ Form . Text > }
108+ { children }
109+ </ FormGroup >
110+ ) ;
111+ }
112+ }
62113
63114SourceCodeField . propTypes = {
64115 input : PropTypes . shape ( {
@@ -76,6 +127,8 @@ SourceCodeField.propTypes = {
76127 label : PropTypes . oneOfType ( [ PropTypes . string , PropTypes . element ] ) ,
77128 readOnly : PropTypes . bool ,
78129 onBlur : PropTypes . func ,
130+ getSnippet : PropTypes . func ,
131+ setSnippet : PropTypes . func ,
79132} ;
80133
81134export default SourceCodeField ;
0 commit comments