JavaScript for WordPress › Forums › Gutenberg Development › Code Editor
- This topic has 9 replies, 2 voices, and was last updated 6 years, 4 months ago by R B ATTENBOROUGH.
-
AuthorPosts
-
April 8, 2018 at 9:50 pm #44652R B ATTENBOROUGHParticipant
http://jsfiddle.net/mofle/tZVsS/
I’ve been inspired to write a Gutenberg block to help show syntax highlighted code snippets in blog posts.
I’m starting a blog and would like to display snippets like you see on CSS Tricks (for example: https://css-tricks.com/keep-pixelated-images-pixelated-as-they-scale/)I’ve got quite far with this. I can display a code editor as a block on the backend and I can then display the code in a read-only version on the front end (which is the intended behaviour). However, although I can specify the type of code on the frontend (by using some JS), I cannot see how to set the “mode” of the code editor component on the back end.
You can see the entire project git hub repo here.
The code for the block itself is here:
/** * Block dependencies */ import icon from './icon'; import './style.scss'; const { CodeEditor } = wp.components; /** * Internal block libraries */ const { __ } = wp.i18n; const { registerBlockType, PlainText } = wp.blocks; /** * Register block */ export default registerBlockType( 'jsforwpblocks/code', { title: __('Example - Code', 'jsforwpblocks'), description: __('How to use the Code component for building your own editable blocks.', 'jsforwpblocks'), category: 'common', icon: icon, keywords: [ __('Banner', 'jsforwpblocks'), __('Call to Action', 'jsforwpblocks'), __('Message', 'jsforwpblocks'), ], attributes: { content: { type: 'string', }, }, edit: props => { const { attributes: { content }, className, setAttributes } = props; return ( <CodeEditor value={ content } onChange={ ( content ) => setAttributes( { content } ) } /> ); }, save: props => { const { attributes: { content } } = props; return ( <div> <div class="message-body"> <p>Code below:</p> <div className="code">{ content }</div> </div> </div> ); } } );
On the front end I’m enqueuing the Code Mirror assets and have an app.js file which looks for instances of the code class and turns them into a read only code editor.
My intention is to include some options on the block for specifying the code type and then setting this (perhaps as a data attribute) on the code class. Then the correct code highlighting can take place.
But I’d really like this code highlighting on the backend as well.
NOTE: I’m still a rookie so I know the code will be shaky at the moment.
April 8, 2018 at 11:12 pm #44663Zac GordonKeymasterCould you use a selector like a radio button in the inspector control that let’s you assign the type of code block on the backend? Then I’m guessing some class or something passed as from an attribute could let the frontend know the kind of code you’re working with. Would that work or address the problem?
April 9, 2018 at 8:19 am #44689R B ATTENBOROUGHParticipantThe problem is the CodeEditor component on the backend. When I’ve setup buttons to select the code mode I don’t know how to communicate this to the component:
<CodeEditor value={ content } onChange={ ( content ) => setAttributes( { content } ) } />
As you can see I can pass the content prop to the element and update the content on change. But I don’t understand how to communicate the type or mode of code to the element so that it shows the appropriate syntax highlighting.
On the front end I’m not using the component but instead creating a div with the class of code where I inject the content (as a string). I then use JS to convert this div it a code editor. I suppose I could do a similar thing on the backend as well but really seeing as WP has added Code Mirror to core it would be nice to use it rather than pulling in the whole library twice…April 9, 2018 at 9:44 am #44698Zac GordonKeymasterOkay so I may still not be following everything completely, but couldn’t you add the attribute you need to the save function as a data attribute or class?
I’m also curious what happens when you use the CodeEditor component in the save method (I haven’t experimented with it yet).
Not sure if it relates, but blocks were not designed to be interactive on the frontend. So if you want a block to have JS run on the frontend you do need to load it separately in a script loaded to the frontend like you’re describing.
Hope this helps a bit? Let me know how the experimentation goes!
April 21, 2018 at 10:09 am #45557R B ATTENBOROUGHParticipantHi Zac good to catch up with you at WordCamp London!
It’s not the front end display I’m struggling with but rather the backend. I want to create a code mirror block which will allow me to edit text in a specified language. So I need to have a way to tell the <CodeEditor> component on the backend what language it should be using. I’ve tried looking at the CodeMirror docs and the Gutenberg docs but I’m scratching my head because the <CodeEditor> component doesn’t seem to have a property for it’s language mode: https://github.com/WordPress/gutenberg/tree/master/components/code-editor
Possibly this element is only intended for html, css and js?
Anyway I’ll have a play around with it.
April 23, 2018 at 8:59 am #45621R B ATTENBOROUGHParticipantActually, it looks like they’ve extended the component now to accept settings!
https://github.com/WordPress/gutenberg/tree/master/components/code-editor
Looking forward to checking this out.
April 23, 2018 at 12:06 pm #45633Zac GordonKeymasterNice! Thanks for posting updates about this! Hope you can get it easily working now ::
April 25, 2018 at 7:50 pm #45790R B ATTENBOROUGHParticipantOkay, very nearly there now. The code editor now accepts settings, so the block now looks like this:
return [ isSelected && <Inspector { ...{setAttributes, ...props} } />, <div> <div> <h4>Language: {language}</h4> </div> <CodeEditor value={ content } settings={Object.assign( { codemirror: { mode: language, lint: true } }) } onChange={ ( content ) => setAttributes( { content } ) } /> </div> ];
I’m providing the language via an inspector block and currently the user can choose between html, javascript and css. When I update the language option this is reflected in the language title changing. However the CodeEditor component doesn’t change. Should I be adding something to the onChange method?
There’s some documentation here: https://github.com/WordPress/gutenberg/tree/master/components/code-editor which suggests
editorRef
andthis.editorInstance.setOption( 'mode', 'css' );
can be used to change modes, but I’m not quite sure how to a) use the editorRef or b) how to change the language for a specific CodeEditor instance (user may want different editors using different languages on the same post).No worries if you can’t help. I appreciate this component is pretty new! (By the way my code on https://github.com/BenAttenborough/rba-codeblock will only work with the Gutenberg taken direct from github).
May 2, 2018 at 12:43 pm #46111R B ATTENBOROUGHParticipantManaged to fix it 🙂 !
I had to pass the instance to the Inspector controls:
edit: props => { const { attributes: { content, language, lineNumbers }, isSelected, setAttributes } = props; return [ isSelected && (<Inspector { ...{setAttributes, ...props, ...{editor: this}} } />), isSelected && (<Controls { ...{setAttributes, ...props, ...{editor: this}} } />), <div> <div> <h4>Language: {language}</h4> </div> <CodeEditor editorRef={ ( ref ) => this.editorInstance = ref } value={ content } settings={Object.assign( { codemirror: { mode: language, lint: true, lineNumbers: lineNumbers, } }, window._wpGutenbergCodeEditorSetting ) } onChange={ ( content, language, lineNumbers ) => setAttributes( { content }, {language}, {lineNumbers}) } /> </div> ]; },
And then within the inspector control I used the editor prop to change the editor instance:
export default class Inspector extends Component { constructor() { super( ...arguments ); } render() { const { attributes: { language }, setAttributes, editor } = this.props; function onChangeLanguage (language) { setAttributes( { language } ); editor.editorInstance.setOption( 'mode', language ); } return ( <InspectorControls> <PanelBody title={ __( 'Snippet settings', 'rba-codeblock' ) } > </PanelBody> <PanelBody> <RadioControl label={ __( 'Language', 'rba-codeblock' ) } selected={ language } options={ [ { label: 'HTML', value: 'htmlmixed' }, { label: 'CSS', value: 'css' }, { label: 'JS', value: 'javascript' } ] } onChange={ onChangeLanguage } /> </PanelBody> </InspectorControls> ); } }
So it finally all works! You can check out the github repo here: https://github.com/BenAttenborough/rba-codeblock
Be warned that this only works with the Gutenberg production code at the moment.May 12, 2018 at 9:21 pm #46971R B ATTENBOROUGHParticipantHey finally got the code snippet block working!
It’s available at: https://github.com/BenAttenborough/rba-codeblock
There still seems to be a bit of a strange bug. For some reason when editing a page with multiple code snippet blocks changing the language or line number settings changes the wrong editor. However upon saving and updating the correct settings should show. Does not affect the front end.
I think this may be because the code block is being updated directly rather than through the React component. Anyway let me know what you think of the block. 🙂 -
AuthorPosts
- You must be logged in to reply to this topic.