Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating a TinyMCE inline editor AND making it visible from a button

Tags:

tinymce-4

I'd like to use TinyMCE 4.1.7 in inline mode. When the user right-clicks a DIV and selects Edit, indicating they want to edit the DIV, I execute

var id= g.currentElement$.attr('id');
            tinymce.init({
                selector: "div#"+id,
                inline:true,
            });

This adds a TinyMCE editor (I know because I catch an AddEditor event) but it doesn't seem to append the editor elements to the DOM (I can't see them in Chrome DevTools Elements tab). For the editor to appear I have to click inside the DIV.

I want to change this behavior so that when the user right-clicks the DIV and selects Edit, my handler will also trigger whatever is triggered now by clicking in the DIV. So after I've launched the editor, as above, I need to call some other method that will append the editor to the DOM and make it visible, so clicking Edit in the context menu is all I need to bring up the TinyMCE editor.

Could someone tell me what I need to do to accomplish this?

(The reason I can't just click the DIV to bring up the editor is that a click already means something else. A single click selects the DIV, where it can be deleted, duplicated, nudged, etc. A drag on the DIV moves it. And a drag on a DIV corner resizes the DIV. A right-click with an Edit option is all I have left.)

Thanks for your help.

Steve

like image 347
Steve Avatar asked Mar 17 '23 15:03

Steve


2 Answers

I got this working as follows. I first run the tinymce init:

var id= g.currentElement$.attr('id');
tinymce.init({
    selector: "div#"+id,
    inline:true,
});

That creates an editor for the element but doesn't render or show it. Rendering and showing the editor normally requires a mousedown on the element.

After stepping through a lot of tinymce code I realized that firing a focusin event on the editor instance is what gets the editor rendered and displayed. So I created a callback for AddEditor. The AddEditor event comes in early in the editor create process, though, and I didn't want to fire focusin until the editor was complete, so at the AddEditor event I get the editor instance and create a callback for "NodeChange," which happens at the end of the editor create.

When NodeCreate comes in I fire a "focusin" on the editor and that renders and displays the editor, as I wanted. A single click, now, runs tinymce init and leaves an inline editor displayed and ready on top of the element.

The total code is:

tinymce.on('AddEditor', function(e) {
    e.editor.on('NodeChange', function(e) {  // now that we know the editor set a callback at "NodeChange."
        e.target.fire("focusin");       // NodeChange is at the end of editor create. Fire focusin to render and show it
    });
});

If anyone sees anything wrong with this I'd be very grateful for any comments.

Thanks

like image 95
Steve Avatar answered Apr 28 '23 13:04

Steve


tinymce.init({
    selector: "div#"+id,
    inline:true,
    setup: function (ed) {
       ed.on('init', function(e) {                        
          e.target.fire("focusin");
       });
    }
});

This will do the trick for the initiating editor instance. Better then globally firing for every single NodeChange event for every single editor instance on the page. (Assuming there multiple editors but also works with single editor.)

BUT WAIT...

There is a better practice using JS Promises. tinymce.init returns a Promise Object.

let tinyMcePromise= tinymce.init({
    selector: "div#"+id,
    inline:true
});

tinyMcePromise.then(function(editors){
    editors[0].focus();
});

Official documentation: https://www.tinymce.com/docs/api/tinymce/root_tinymce/#init

Beware: Some older versions of tinyMce have a bug about init Promise.

like image 25
Zortext Avatar answered Apr 28 '23 11:04

Zortext