Как использовать ссылки в среднем редакторе?

Я пробовал отличный редактор средних размеров. Проблема, с которой я столкнулась, заключается в том, что я не могу получить ссылки на "работу".

В самом простом, здесь некоторые HTML/JS для демонстрации проблемы:

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="#" onclick="location.href='https://cdn.jsdelivr.net/medium-editor/latest/css/themes/beagle.min.css'; return false;" type="text/css">
</head>
<body>
  <div class='editable'>
    Hello world.  <a href="#" onclick="location.href='http://www.google.com'; return false;">link</a>
  </div>
</body>
</html>

Javascript:

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

Эта скрипка демонстрирует проблему (используя код выше).

  • Если вы наведите указатель мыши на ссылку, появится всплывающее окно.
  • Если вы нажмете ссылку, ничего не произойдет.
  • Если вы щелкнете всплывающее окно, появится форма, где вы можете отредактировать ссылку.

Мне кажется, что нажатие на ссылку должно занять меня везде, где href ссылка href. Единственный способ использовать ссылку - щелкнуть правой кнопкой мыши и открыть ее на новой вкладке или в новом окне - что я не хочу просить моих пользователей делать.

Я чувствую, что мне нужно пропустить что-то простое в конфигурации (либо Параметры предварительного просмотра якоря, либо Параметры формы анкера). К сожалению, я этого не вижу.

В моем фактическом приложении я не использую jQuery, но я использую angularjs.Если ответа строго среднего редактора не существует, я могу вернуться к использованию базового JS или чего-либо, что обеспечивает угловой js.

Ответы

Ответ 1

То, что я действительно хотел, когда задавал вопрос, было поведение, подобное Google Docs, когда оно находится в режиме редактирования (как описано Nate Mielnik). Я открыл проблему на трекере Medium Editor, и они решили не реализовывать ее как часть основного редактора среды, но они отметили, что им будет приятно, если кто-то добавит эту функциональность в качестве расширения.

Итак, я решил реализовать эту функциональность как расширение, как предлагалось. Он может быть найден как часть MediumTools 1. Проект все еще находится на очень ранних этапах (например, я ничего не сделал, чтобы стиль выглядел лучше, или чтобы использовать более эффективные методы оценки и т.д., Но мы с радостью примем Pull Requests для этого).

Чувства кода выглядят так:

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();
      }
    }
  });

В качестве объяснения я просто использую средний вкус прототипического наследования для "подкласса" оригинального/встроенного расширения AnchorPreview. Я переопределяю метод getTemplate чтобы добавить дополнительные ссылки в разметку. Затем я много взял из базовой реализации getPreview, но я привязал новые действия к каждой из ссылок, если это необходимо. Наконец, мне нужно было выполнить действие для "развязывания" ссылки при нажатии "Удалить", поэтому я добавил для этого метод. Метод unlink, вероятно, можно было бы сделать немного лучше, используя контентоспособную магию (чтобы убедиться, что она является частью стека отмены браузера), но я не тратил время на это (хотя это сделало бы хороший запрос Pull для любой заинтересованный :-).

1 В настоящее время это единственная часть, но я надеюсь, что в какой-то момент это изменится.,,

Ответ 3

Таким образом, средний редактор построен поверх встроенной поддержки браузера для contenteditable элементов. Когда вы создаете экземпляр medium-editor, он добавляет атрибут contenteditable=true в любой элемент (ы), который вы ему предоставили.

По умолчанию, поскольку текст теперь доступен для редактирования (атрибут contenteditable делает браузер обработанным как текст WYSIWYG), браузер больше не поддерживает щелчок по ссылкам для навигации. Таким образом, средний редактор не блокирует эти клики по ссылке, браузеры делают это неотъемлемо как часть редактирования текста.

medium-editor имеет встроенные расширения для взаимодействия со ссылками:

  • удлинение анкера
    • позволяет добавлять/удалять ссылки
  • расширение анкера-предварительного просмотра
    • показывает всплывающую подсказку при наведении ссылки
    • при нажатии на всплывающую подсказку, позволяет редактировать href ссылки через расширение привязки

Я думаю, что основная цель редактора - это недоразумение здесь. Редактор позволяет редактировать текст, а для того, чтобы добавлять/удалять/обновлять ссылки, вы должны иметь возможность щелкнуть по нему без автоматического перехода. Это то, что я называю "режимом редактирования".

Однако html, созданный в результате редактирования, является допустимым html, и если вы возьмете этот html и поместите его внутри элемента, у которого нет атрибута contenteditable=true, все будет работать так, как ожидалось. Я думаю об этом как о "режиме публикации",

Я смотрю на редакторы, такие как слова или документы Google, и вы видите подобное поведение, когда при редактировании документа ссылки не просто перемещаются, когда вы нажимаете на них, вы должны фактически выбирать их перемещение через отдельный после нажатия ссылки. Однако в "опубликованной" версии документа щелчок по ссылке фактически откроет окно браузера и перемещается туда.

Я думаю, что это делает хорошее предложение в качестве улучшения существующего расширения анкерного предварительного просмотра. Возможно, всплывающая подсказка, которая появляется при наведении ссылки, может иметь в ней несколько параметров (например, "Редактировать ссылку | Удалить ссылку". Перейти к URL-адресу).

TL;DR;

Ссылки не доступны для навигации по клику при редактировании текста в браузере через встроенную поддержку WYSIWYG (contenteditable). Если не в режиме редактирования, ссылки будут работать, как ожидалось. Это может значительно улучшить расширение предварительного просмотра якоря-редактора.

Ответ 4

Исходя из некоторых замечаний от @Valijon в комментариях, я смог заставить его работать, используя следующий код:

var iElement = angular.element(mediumEditorElement);

iElement.on('click', function(event) {
  if (
      event.target && event.target.tagName == 'A' &&
      event.target.href && !event.defaultPrevented) {
    $window.open(event.target.href, '_blank');
  }
});

Я думаю, что ключ заключается в том, что, по-видимому, редактор позволяет событию распространять элементы предка, поэтому я смог просто прослушать щелчок на элементе редактора верхнего уровня.

Здесь $window является угловым сервисом $window Если вы не используете angularjs, window будет делать трюк, и я использовал angular.element чтобы облегчить реестр прослушивателя событий, но вы можете сделать это старомодно (или используя структура JS по вашему выбору).