Switch between editor being editable or not

I’m afraid I’ve tried my best at reading through the docs, but still am unable to get a grasp on how I can use the EditorView.editable facet to toggle between making an editor editable and non-editable.

I’ve tried a number of things, but my most recent attempt was to setup the editor like so:

this.editor = new EditorView({
	state: EditorState.create({extensions: [
		basicSetup,
		javascript(),
		listenerExtension,
		EditorView.editable.of(!this.props.isDisabled)
	]}),
	parent: this.codeMirror.current
});

Here you can see if this.props.isDisabled is initially true, then it will set the facet to false, making it non-editable.

Then to be able to toggle the editor to editable later on I’m unsure about. How can I take this.editor and toggle the editor to be editable in this current state?

Any help would be greatly appreciated.

As an aside, I think I saw somewhere in another message, but can someone confirm, that a wrapper, or alternative API will be provided for such configurations and simple toggling of options in future? I was just curious and wanted to check.

Thanks!

In order to dynamically enable/disable an extension (which is what EditorView.editable is), you’ll have to tag it. I.e., if you do something like this…

let editableTag = Symbol()
let state = EditorState.create({extendions: [
  /* ... */
  tagExtension(editableTag, EditorView.editable.of(false))
]})

function setEditable(view: EditorView, value: boolean) {
  view.update({
    reconfigure: {[editableTag]: EditorView.editable.of(value)}
  })
}

You can call setEditable to change the content of your tagged extension.

Thank you - this makes a lot of sense :+1:

I wonder where does tagExtension function comes from. I don’t see it anywhere in Reference Manual

Note that that post is from 2020, before the interface stabilized. You’ll want to use a compartment to do something similar with the current interface.

That’s what I’ve originally found in manual but then I failed in figuring out how I can turn Facet returned by this static method could be turned into Compartment. Searching for the specific issue brought me to this topic.

Looking more into Configuration example I think expected solution should be something along the:

// define some "global" constant reference to new Compartment
const editableCompartment = new Compartment;

// When initializing new state use this compartment to configure editable state
const state = EditorState.create({
    doc: file.content,
    extensions: [
        history(),
        keymap.of([...defaultKeymap, ...historyKeymap]),
        lineNumbers(),
        gutter({ class: "cm-mygutter" }),
        language(),
        syntaxHighlighting(defaultHighlightStyle),
        EditorView.updateListener.of(this.updatedCallback.bind(this)),
        editableCompartment.of(EditorView.editable.of(false)),
    ]
});

// reuse the Compartment instance to alter the editable state
// this.cm being reference to EditorView
this.cm.dispatch({
    effects: editableCompartment.reconfigure(EditorView.editable.of(true))
});