22 * @output wp-admin/js/code-editor.js
33 */
44
5+ /* eslint-env es2020 */
6+
57if ( 'undefined' === typeof window . wp ) {
68 /**
79 * @namespace wp
@@ -44,7 +46,7 @@ if ( 'undefined' === typeof window.wp.codeEditor ) {
4446 * @param {Function } settings.onChangeLintingErrors - Callback for when there are changes to linting errors.
4547 * @param {Function } settings.onUpdateErrorNotice - Callback to update error notice.
4648 *
47- * @return {void }
49+ * @return {Function } Update error notice function.
4850 */
4951 function configureLinting ( editor , settings ) { // eslint-disable-line complexity
5052 var currentErrorAnnotations = [ ] , previouslyShownErrorAnnotations = [ ] ;
@@ -80,7 +82,7 @@ if ( 'undefined' === typeof window.wp.codeEditor ) {
8082 }
8183
8284 /*
83- * Note that rules must be sent in the "deprecated" lint.options property
85+ * Note that rules must be sent in the "deprecated" lint.options property
8486 * to prevent linter from complaining about unrecognized options.
8587 * See <https://github.com/codemirror/CodeMirror/pull/4944>.
8688 */
@@ -207,6 +209,8 @@ if ( 'undefined' === typeof window.wp.codeEditor ) {
207209 updateErrorNotice ( ) ;
208210 }
209211 } ) ;
212+
213+ return updateErrorNotice ;
210214 }
211215
212216 /**
@@ -259,6 +263,7 @@ if ( 'undefined' === typeof window.wp.codeEditor ) {
259263 * @typedef {object } wp.codeEditor~CodeEditorInstance
260264 * @property {object } settings - The code editor settings.
261265 * @property {CodeMirror } codemirror - The CodeMirror instance.
266+ * @property {Function } updateErrorNotice - Force update the error notice.
262267 */
263268
264269 /**
@@ -280,7 +285,7 @@ if ( 'undefined' === typeof window.wp.codeEditor ) {
280285 * @return {CodeEditorInstance } Instance.
281286 */
282287 wp . codeEditor . initialize = function initialize ( textarea , settings ) {
283- var $textarea , codemirror , instanceSettings , instance ;
288+ var $textarea , codemirror , instanceSettings , instance , updateErrorNotice ;
284289 if ( 'string' === typeof textarea ) {
285290 $textarea = $ ( '#' + textarea ) ;
286291 } else {
@@ -292,16 +297,33 @@ if ( 'undefined' === typeof window.wp.codeEditor ) {
292297
293298 codemirror = wp . CodeMirror . fromTextArea ( $textarea [ 0 ] , instanceSettings . codemirror ) ;
294299
295- configureLinting ( codemirror , instanceSettings ) ;
300+ updateErrorNotice = configureLinting ( codemirror , instanceSettings ) ;
296301
297302 instance = {
298303 settings : instanceSettings ,
299- codemirror : codemirror
304+ codemirror,
305+ updateErrorNotice,
300306 } ;
301307
302308 if ( codemirror . showHint ) {
303- codemirror . on ( 'keyup' , function ( editor , event ) { // eslint-disable-line complexity
304- var shouldAutocomplete , isAlphaKey = / ^ [ a - z A - Z ] $ / . test ( event . key ) , lineBeforeCursor , innerMode , token ;
309+ codemirror . on ( 'inputRead' , function ( editor , change ) {
310+ var shouldAutocomplete , isAlphaKey , lineBeforeCursor , innerMode , token , char ;
311+
312+ // Only trigger autocompletion for typed input or IME composition.
313+ if ( '+input' !== change . origin && ! change . origin . startsWith ( '*compose' ) ) {
314+ return ;
315+ }
316+
317+ // Only trigger autocompletion for single-character inputs.
318+ // The text property is an array of strings, one for each line.
319+ // We check that there is only one line and that line has only one character.
320+ if ( 1 !== change . text . length || 1 !== change . text [ 0 ] . length ) {
321+ return ;
322+ }
323+
324+ char = change . text [ 0 ] ;
325+ isAlphaKey = / ^ [ a - z A - Z ] $ / . test ( char ) ;
326+
305327 if ( codemirror . state . completionActive && isAlphaKey ) {
306328 return ;
307329 }
@@ -315,26 +337,30 @@ if ( 'undefined' === typeof window.wp.codeEditor ) {
315337 innerMode = wp . CodeMirror . innerMode ( codemirror . getMode ( ) , token . state ) . mode . name ;
316338 lineBeforeCursor = codemirror . doc . getLine ( codemirror . doc . getCursor ( ) . line ) . substr ( 0 , codemirror . doc . getCursor ( ) . ch ) ;
317339 if ( 'html' === innerMode || 'xml' === innerMode ) {
318- shouldAutocomplete =
319- '<' === event . key ||
320- '/' === event . key && 'tag' === token . type ||
321- isAlphaKey && 'tag' === token . type ||
322- isAlphaKey && 'attribute' === token . type ||
323- '=' === token . string && token . state . htmlState && token . state . htmlState . tagName ;
340+ shouldAutocomplete = (
341+ '<' === char ||
342+ ( '/' === char && 'tag' === token . type ) ||
343+ ( isAlphaKey && 'tag' === token . type ) ||
344+ ( isAlphaKey && 'attribute' === token . type ) ||
345+ ( '=' === char && (
346+ token . state . htmlState ?. tagName ||
347+ token . state . curState ?. htmlState ?. tagName
348+ ) )
349+ ) ;
324350 } else if ( 'css' === innerMode ) {
325351 shouldAutocomplete =
326352 isAlphaKey ||
327- ':' === event . key ||
328- ' ' === event . key && / : \s + $ / . test ( lineBeforeCursor ) ;
353+ ':' === char ||
354+ ( ' ' === char && / : \s + $ / . test ( lineBeforeCursor ) ) ;
329355 } else if ( 'javascript' === innerMode ) {
330- shouldAutocomplete = isAlphaKey || '.' === event . key ;
356+ shouldAutocomplete = isAlphaKey || '.' === char ;
331357 } else if ( 'clike' === innerMode && 'php' === codemirror . options . mode ) {
332- shouldAutocomplete = 'keyword' === token . type || 'variable' === token . type ;
358+ shouldAutocomplete = isAlphaKey && ( 'keyword' === token . type || 'variable' === token . type ) ;
333359 }
334360 if ( shouldAutocomplete ) {
335361 codemirror . showHint ( { completeSingle : false } ) ;
336362 }
337- } ) ;
363+ } ) ;
338364 }
339365
340366 // Facilitate tabbing out of the editor.
0 commit comments