javascriptmedium-editor

How to use links in Medium Editor?


I've been trying out the excellent Medium Editor. The problem that I've been having is that I can't seem to get links to "work".

At the simplest, here's some HTML/JS to use to demonstrate the problem:

HTML:

<html>
<head>
  <script src="//cdn.jsdelivr.net/medium-editor/latest/js/medium-editor.min.js"></script>
  <link rel="stylesheet" href="//cdn.jsdelivr.net/medium-editor/latest/css/medium-editor.min.css" type="text/css" media="screen" charset="utf-8">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/medium-editor/latest/css/themes/beagle.min.css" type="text/css">
</head>
<body>
  <div class='editable'>
    Hello world.  <a href="http://www.google.com">link</a>
  </div>
</body>
</html>

Javascript:

var editor = new MediumEditor('.editable');

This fiddle demonstrates the problem (using the code above).

It seems to me that clicking the link should take me wherever the link's href is targeting. The only way to use the link is to right click and either open in a new tab or new window -- which I don't want to ask my users to do.

I feel like I must be missing something simple in the configuration (either the Anchor Preview Options or the Anchor Form Options). Unfortunately, I'm not seeing it.

In my actual application, I'm not using jQuery, but I am using angularjs. If a strictly Medium Editor answer doesn't exist, I can fall back to using basic JS or anything that angularjs provides.


Solution

  • What I really wanted when I asked the question was behavior similar to Google Docs when in "edit" mode (as described by Nate Mielnik). I opened an issue on the Medium Editor tracker and they decided not to implement it as part of the core medium editor, but they noted that they would be happy to have someone add that functionality as an extension.

    So, I decided to implement that functionality as an extension as suggested. It can be found as part of MediumTools1. The project is still in very early stages (e.g. I haven't done anything to make the styling look better, or to use better minifying practices, etc. but we'll happily accept Pull Requests for that).

    The guts of the code look like this:

    var ClassName = {
      INNER: 'medium-editor-toolbar-anchor-preview-inner',
      INNER_CHANGE: 'medium-editor-toolbar-anchor-preview-inner-change',
      INNER_REMOVE: 'medium-editor-toolbar-anchor-preview-inner-remove'
    }
    
    var AnchorPreview = MediumEditor.extensions.anchorPreview;
    GdocMediumAnchorPreview = MediumEditor.Extension.extend.call(
      AnchorPreview, {
    
        /** @override */
        getTemplate: function () {
          return '<div class="medium-editor-toolbar-anchor-preview">' +
            '  <a class="' + ClassName.INNER + '"></a>' +
            '  -' +
            '  <a class="' + ClassName.INNER_CHANGE + '">Change</a>' +
            '  |' +
            '  <a class="' + ClassName.INNER_REMOVE + '">Remove</a>' +
            '</div>';
        },
    
        /** @override */
        createPreview: function () {
          var el = this.document.createElement('div');
    
          el.id = 'medium-editor-anchor-preview-' + this.getEditorId();
          el.className = 'medium-editor-anchor-preview';
          el.innerHTML = this.getTemplate();
    
          var targetBlank =
              this.getEditorOption('targetBlank') ||
              this.getEditorOption('gdocAnchorTargetBlank');
          if (targetBlank) {
            el.querySelector('.' + ClassName.INNER).target = '_blank';
          }
    
          var changeEl = el.querySelector('.' + ClassName.INNER_CHANGE);
          this.on(changeEl, 'click', this.handleClick.bind(this));
    
          var unlinkEl = el.querySelector('.' + ClassName.INNER_REMOVE);
          this.on(unlinkEl, 'click', this.handleUnlink.bind(this));
    
          return el;
        },
    
        /** Unlink the currently active anchor. */
        handleUnlink: function() {
          var activeAnchor = this.activeAnchor;
          if (activeAnchor) {
            this.activeAnchor.outerHTML = this.activeAnchor.innerHTML;
            this.hidePreview();
          }
        }
      });
    

    As an explanation, I just use medium's flavor of prototypical inheritance to "subclass" the original/builtin AnchorPreview extension. I override the getTemplate method to add the additional links into the markup. Then I borrowed a lot from the base implementation of getPreview, but I bound new actions to each of the links as appropriate. Finally, I needed to have an action for "unlinking" the link when "Remove" is clicked, so I added a method for that. The unlink method could probably be done a little better using contenteditable magic (to make sure that it is part of the browser's undo stack), but I didn't spend the time to figure that out (though it would make a good Pull Request for anyone interested :-).

    1Currently, it's the only part, but I hope that'll change at some point. . .