Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 34 additions & 14 deletions src/js/_enqueues/wp/code-editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ if ( 'undefined' === typeof window.wp.codeEditor ) {
* @param {Function} settings.onChangeLintingErrors - Callback for when there are changes to linting errors.
* @param {Function} settings.onUpdateErrorNotice - Callback to update error notice.
*
* @return {void}
* @return {Function} Update error notice function.
*/
function configureLinting( editor, settings ) { // eslint-disable-line complexity
var currentErrorAnnotations = [], previouslyShownErrorAnnotations = [];
Expand Down Expand Up @@ -82,7 +82,7 @@ if ( 'undefined' === typeof window.wp.codeEditor ) {
}

/*
* Note that rules must be sent in the "deprecated" lint.options property
* Note that rules must be sent in the "deprecated" lint.options property
* to prevent linter from complaining about unrecognized options.
* See <https://github.com/codemirror/CodeMirror/pull/4944>.
Comment on lines +85 to 87
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know exactly what's going on in this comment, but it caught my attention.

codemirror/codemirror5#4944 was merged so this may be out of date?

Not necessary to change anything in this PR.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good callout. After merging this I intend to do an overall pass on this file and theme-plugin-editor.js to clean up stuff like this. I'm going to fix types and update docs. Once everything is pristine, then this should greatly help with plotting a course for v6.

*/
Expand Down Expand Up @@ -209,6 +209,8 @@ if ( 'undefined' === typeof window.wp.codeEditor ) {
updateErrorNotice();
}
});

return updateErrorNotice;
}

/**
Expand Down Expand Up @@ -261,6 +263,7 @@ if ( 'undefined' === typeof window.wp.codeEditor ) {
* @typedef {object} wp.codeEditor~CodeEditorInstance
* @property {object} settings - The code editor settings.
* @property {CodeMirror} codemirror - The CodeMirror instance.
* @property {Function} updateErrorNotice - Force update the error notice.
*/

/**
Expand All @@ -282,7 +285,7 @@ if ( 'undefined' === typeof window.wp.codeEditor ) {
* @return {CodeEditorInstance} Instance.
*/
wp.codeEditor.initialize = function initialize( textarea, settings ) {
var $textarea, codemirror, instanceSettings, instance;
var $textarea, codemirror, instanceSettings, instance, updateErrorNotice;
if ( 'string' === typeof textarea ) {
$textarea = $( '#' + textarea );
} else {
Expand All @@ -294,16 +297,33 @@ if ( 'undefined' === typeof window.wp.codeEditor ) {

codemirror = wp.CodeMirror.fromTextArea( $textarea[0], instanceSettings.codemirror );

configureLinting( codemirror, instanceSettings );
updateErrorNotice = configureLinting( codemirror, instanceSettings );

instance = {
settings: instanceSettings,
codemirror: codemirror
codemirror,
updateErrorNotice,
};

if ( codemirror.showHint ) {
codemirror.on( 'keyup', function( editor, event ) { // eslint-disable-line complexity
var shouldAutocomplete, isAlphaKey = /^[a-zA-Z]$/.test( event.key ), lineBeforeCursor, innerMode, token;
codemirror.on( 'inputRead', function( editor, change ) {
var shouldAutocomplete, isAlphaKey, lineBeforeCursor, innerMode, token, char;

// Only trigger autocompletion for typed input or IME composition.
if ( '+input' !== change.origin && ! change.origin.startsWith( '*compose' ) ) {
return;
}

// Only trigger autocompletion for single-character inputs.
// The text property is an array of strings, one for each line.
// We check that there is only one line and that line has only one character.
if ( 1 !== change.text.length || 1 !== change.text[0].length ) {
return;
}

char = change.text[0];
isAlphaKey = /^[a-zA-Z]$/.test( char );

if ( codemirror.state.completionActive && isAlphaKey ) {
return;
}
Expand All @@ -318,29 +338,29 @@ if ( 'undefined' === typeof window.wp.codeEditor ) {
lineBeforeCursor = codemirror.doc.getLine( codemirror.doc.getCursor().line ).substr( 0, codemirror.doc.getCursor().ch );
if ( 'html' === innerMode || 'xml' === innerMode ) {
shouldAutocomplete = (
'<' === event.key ||
( '/' === event.key && 'tag' === token.type ) ||
'<' === char ||
( '/' === char && 'tag' === token.type ) ||
( isAlphaKey && 'tag' === token.type ) ||
( isAlphaKey && 'attribute' === token.type ) ||
( '=' === event.key && (
( '=' === char && (
token.state.htmlState?.tagName ||
token.state.curState?.htmlState?.tagName
) )
);
} else if ( 'css' === innerMode ) {
shouldAutocomplete =
isAlphaKey ||
':' === event.key ||
( ' ' === event.key && /:\s+$/.test( lineBeforeCursor ) );
':' === char ||
( ' ' === char && /:\s+$/.test( lineBeforeCursor ) );
} else if ( 'javascript' === innerMode ) {
shouldAutocomplete = isAlphaKey || '.' === event.key;
shouldAutocomplete = isAlphaKey || '.' === char;
} else if ( 'clike' === innerMode && 'php' === codemirror.options.mode ) {
shouldAutocomplete = isAlphaKey && ( 'keyword' === token.type || 'variable' === token.type );
}
if ( shouldAutocomplete ) {
codemirror.showHint( { completeSingle: false } );
}
});
} );
}

// Facilitate tabbing out of the editor.
Expand Down
30 changes: 29 additions & 1 deletion src/js/_enqueues/wp/theme-plugin-editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
* @output wp-admin/js/theme-plugin-editor.js
*/

/* eslint no-magic-numbers: ["error", { "ignore": [-1, 0, 1] }] */
/* eslint-env es2020 */

/* eslint no-magic-numbers: ["error", { "ignore": [-1, 0, 1, 9, 1000] }] */

if ( ! window.wp ) {
window.wp = {};
Expand Down Expand Up @@ -81,6 +83,18 @@ wp.themePluginEditor = (function( $ ) {
component.docsLookUpButton.prop( 'disabled', false );
}
} );

// Initiate saving the file when not focused in CodeMirror or when the user has syntax highlighting turned off.
$( window ).on( 'keydown', function( event ) {
if (
( event.ctrlKey || event.metaKey ) &&
( 's' === event.key.toLowerCase() ) &&
( ! component.instance || ! component.instance.codemirror.hasFocus() )
) {
event.preventDefault();
component.form.trigger( 'submit' );
}
} );
};

/**
Expand Down Expand Up @@ -191,6 +205,10 @@ wp.themePluginEditor = (function( $ ) {
return;
}

if ( component.instance && component.instance.updateErrorNotice ) {
component.instance.updateErrorNotice();
}

// Scroll to the line that has the error.
if ( component.lintErrors.length ) {
component.instance.codemirror.setCursor( component.lintErrors[0].from.line );
Expand Down Expand Up @@ -399,6 +417,16 @@ wp.themePluginEditor = (function( $ ) {
editor = wp.codeEditor.initialize( $( '#newcontent' ), codeEditorSettings );
editor.codemirror.on( 'change', component.onChange );

function onSaveShortcut() {
component.form.trigger( 'submit' );
}

editor.codemirror.setOption( 'extraKeys', {
...( editor.codemirror.getOption( 'extraKeys' ) || {} ),
'Ctrl-S': onSaveShortcut,
'Cmd-S': onSaveShortcut,
} );

// Improve the editor accessibility.
$( editor.codemirror.display.lineDiv )
.attr({
Expand Down
Loading