-
Notifications
You must be signed in to change notification settings - Fork 4.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #4348 from WordPress/add/syntax-highlighting-to-ht…
…ml-block Add CodeMirror to the HTML block
- Loading branch information
Showing
11 changed files
with
404 additions
and
50 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,25 @@ | ||
.wp-block-html.blocks-plain-text { | ||
font-family: $editor-html-font; | ||
font-size: $text-editor-font-size; | ||
color: $dark-gray-800; | ||
padding: .8em 1.6em; | ||
overflow-x: auto !important; | ||
border: 1px solid $light-gray-500; | ||
border-radius: 4px; | ||
.gutenberg .wp-block-html { | ||
iframe { | ||
display: block; | ||
|
||
// Disable pointer events so that we can click on the block to select it | ||
pointer-events: none; | ||
} | ||
|
||
.CodeMirror { | ||
border-radius: 4px; | ||
border: 1px solid $light-gray-500; | ||
font-family: $editor-html-font; | ||
font-size: $text-editor-font-size; | ||
height: auto; | ||
} | ||
|
||
.CodeMirror-gutters { | ||
background: $white; | ||
border-right: none; | ||
} | ||
|
||
.CodeMirror-lines { | ||
padding: 8px 8px 8px 0; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,22 @@ | ||
// Jest Snapshot v1, https://goo.gl/fbAQLP | ||
|
||
exports[`core/html block edit matches snapshot 1`] = ` | ||
<textarea | ||
aria-label="HTML" | ||
class="blocks-plain-text wp-block-html" | ||
rows="1" | ||
/> | ||
<div | ||
class="wp-block-html" | ||
> | ||
<div | ||
class="components-placeholder" | ||
> | ||
<div | ||
class="components-placeholder__label" | ||
/> | ||
<div | ||
class="components-placeholder__fieldset" | ||
> | ||
<span | ||
class="spinner is-active" | ||
/> | ||
</div> | ||
</div> | ||
</div> | ||
`; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
CodeEditor | ||
======= | ||
|
||
CodeEditor is a React component that provides the user with a code editor | ||
that has syntax highlighting and linting. | ||
|
||
The components acts as a drop-in replacement for a <textarea>, and uses the | ||
CodeMirror library that is provided as part of WordPress Core. | ||
|
||
## Usage | ||
|
||
```jsx | ||
import { CodeEditor } from '@wordpress/components'; | ||
|
||
function editCode() { | ||
return ( | ||
<CodeEditor | ||
value={ '<p>This is some <b>HTML</b> code that will have syntax highlighting!</p>' } | ||
onChange={ value => console.log( value ) } | ||
/> | ||
); | ||
} | ||
``` | ||
|
||
## Props | ||
|
||
The component accepts the following props: | ||
|
||
### value | ||
|
||
The source code to load into the code editor. | ||
|
||
- Type: `string` | ||
- Required: Yes | ||
|
||
### focus | ||
|
||
Whether or not the code editor should be focused. | ||
|
||
- Type: `boolean` | ||
- Required: No | ||
|
||
### onFocus | ||
|
||
The function called when the editor is focused. | ||
|
||
- Type: `Function` | ||
- Required: No | ||
|
||
### onChange | ||
|
||
The function called when the user has modified the source code via the | ||
editor. It is passed the new value as an argument. | ||
|
||
- Type: `Function` | ||
- Required: No |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
/** | ||
* WordPress dependencies | ||
*/ | ||
import { Component } from '@wordpress/element'; | ||
import { keycodes } from '@wordpress/utils'; | ||
|
||
/** | ||
* Module constants | ||
*/ | ||
const { UP, DOWN } = keycodes; | ||
|
||
class CodeEditor extends Component { | ||
constructor() { | ||
super( ...arguments ); | ||
|
||
this.onFocus = this.onFocus.bind( this ); | ||
this.onBlur = this.onBlur.bind( this ); | ||
this.onCursorActivity = this.onCursorActivity.bind( this ); | ||
this.onKeyHandled = this.onKeyHandled.bind( this ); | ||
} | ||
|
||
componentDidMount() { | ||
const instance = wp.codeEditor.initialize( this.textarea, window._wpGutenbergCodeEditorSettings ); | ||
this.editor = instance.codemirror; | ||
|
||
this.editor.on( 'focus', this.onFocus ); | ||
this.editor.on( 'blur', this.onBlur ); | ||
this.editor.on( 'cursorActivity', this.onCursorActivity ); | ||
this.editor.on( 'keyHandled', this.onKeyHandled ); | ||
|
||
this.updateFocus(); | ||
} | ||
|
||
componentDidUpdate( prevProps ) { | ||
if ( this.props.value !== prevProps.value && this.editor.getValue() !== this.props.value ) { | ||
this.editor.setValue( this.props.value ); | ||
} | ||
|
||
if ( this.props.focus !== prevProps.focus ) { | ||
this.updateFocus(); | ||
} | ||
} | ||
|
||
componentWillUnmount() { | ||
this.editor.on( 'focus', this.onFocus ); | ||
this.editor.off( 'blur', this.onBlur ); | ||
this.editor.off( 'cursorActivity', this.onCursorActivity ); | ||
this.editor.off( 'keyHandled', this.onKeyHandled ); | ||
|
||
this.editor.toTextArea(); | ||
this.editor = null; | ||
} | ||
|
||
onFocus() { | ||
if ( this.props.onFocus ) { | ||
this.props.onFocus(); | ||
} | ||
} | ||
|
||
onBlur( editor ) { | ||
if ( this.props.onChange ) { | ||
this.props.onChange( editor.getValue() ); | ||
} | ||
} | ||
|
||
onCursorActivity( editor ) { | ||
this.lastCursor = editor.getCursor(); | ||
} | ||
|
||
onKeyHandled( editor, name, event ) { | ||
/* | ||
* Pressing UP/DOWN should only move focus to another block if the cursor is | ||
* at the start or end of the editor. | ||
* | ||
* We do this by stopping UP/DOWN from propagating if: | ||
* - We know what the cursor was before this event; AND | ||
* - This event caused the cursor to move | ||
*/ | ||
if ( event.keyCode === UP || event.keyCode === DOWN ) { | ||
const areCursorsEqual = ( a, b ) => a.line === b.line && a.ch === b.ch; | ||
if ( this.lastCursor && ! areCursorsEqual( editor.getCursor(), this.lastCursor ) ) { | ||
event.stopImmediatePropagation(); | ||
} | ||
} | ||
} | ||
|
||
updateFocus() { | ||
if ( this.props.focus && ! this.editor.hasFocus() ) { | ||
// Need to wait for the next frame to be painted before we can focus the editor | ||
window.requestAnimationFrame( () => { | ||
this.editor.focus(); | ||
} ); | ||
} | ||
|
||
if ( ! this.props.focus && this.editor.hasFocus() ) { | ||
document.activeElement.blur(); | ||
} | ||
} | ||
|
||
render() { | ||
return <textarea ref={ ref => ( this.textarea = ref ) } value={ this.props.value } />; | ||
} | ||
} | ||
|
||
export default CodeEditor; |
Oops, something went wrong.