Ionaru / easy-markdown-editor

EasyMDE: A simple, beautiful, and embeddable JavaScript Markdown editor. Delightful editing for beginners and experts alike. Features built-in autosaving and spell checking.
https://stackblitz.com/edit/easymde
MIT License
2.39k stars 316 forks source link

Editor instances in Bootstrap tabs require click to load #208

Closed PackeTsar closed 4 years ago

PackeTsar commented 4 years ago

Describe the bug When loading multiple instances of the editor (with existing content) hidden by Bootstrap4 nav tabs, you have to click in the editor area to show the existing content.

To Reproduce Steps to reproduce the behavior:

  1. Visit reproduced problem at https://jsfiddle.net/0puogLhz/1/
  2. Click on the 'Page 1' or 'Page 2' field (tab)
  3. Nothing will show in the editor
  4. Click inside the editor space and the existing content will show up

Expected behavior Existing content should show when tab is clicked and that tab's editor is revealed. It should not require you to click inside the editor

Version information

Additional context Perhaps I am doing something wrong here or there is an easy workaround I could implement due to my unique use case. Any help is appreciated.

PackeTsar commented 4 years ago

It is also worth mentioning that once you click inside the content area, in a page, you can move between pages and the content will continue to show back up OK. You only need to do it once. I have tried to simulate a click inside the content with the below, but with no success.

$('div.CodeMirror-code').each(function(){
    $(this).trigger('click');
}
chronon commented 4 years ago

I was running into similar issues with Boostrap collapse, calling codemirror.refresh() on editor instances fixed it for me. Relevant discussion here.

PackeTsar commented 4 years ago

Thanks for the tip! I just tried calling setTimeout(function() { easyMDE.codemirror.refresh(); }, 100); on each instance as I create them. It worked to display the initial page which shows up at loading time (so it gave me a step in the right direction), but not to show the hidden pages when they are shown. Let me know if you think of anything else. I'll keep working it and report back if I solve it.

PackeTsar commented 4 years ago

I was able to fix (more like workaround) the issue with the below script. Just having it trigger off of a click on the tab to expose the content. Code works in prod and in the POC here: https://jsfiddle.net/r5Lkv7oe/

I also found the question being asked here and they recommended using the autorefresh feature in CodeMirror. I am quite new to JS and I know EasyMDE is a wrapper around CodeMirror, and I don't see a way to activate that feature when instantiating an EasyMDE instance in the options list. Not sure if this is something I could reach in and turn on when I instantiate an editor, or if it is something that would need to be added to the EasyMDE code to be usable.

<script>
  $(document).ready(function() {  // Run after the page loads
    // For each <textarea> element in the id="page_content" div
    $('#page_content textarea').each(function(){
      // Create the editor instance from the <textarea> element
      var editor = new EasyMDE({element: this});
      // Save the codemirror instance returned from EasyMDE into the
      //     <textarea> element so we can call the refresh() function
      //     in it later when the tab is shown (the <textarea> element)
      //     won't contain a copy of the object by default so we need
      //     to tuck it away there.
      editor.element.cmirror = editor.codemirror;
    });
    // Trigger from a click on the tab link which displays the tab
    //     contents.
    $('a[data-toggle="tab"]').on('click', function() {
      // Grab the name attribute off of the <a> element
      var tabname = $(this).attr('name');
      // Delay the call of our refresh() function with setTimeout
      setTimeout(function() {
        // Call the refresh() function of the codemirror instance
        //     stowed away in our <textarea> element
        $('#'+tabname+' textarea')[0].cmirror.refresh();
      }, 250); // But wait 250 msec to call that function
    });
  });
</script>
PackeTsar commented 4 years ago

Going to close this issue since I found a workaround.