«Если рабочий хочет хорошо выполнять свою работу, он должен сначала заточить свои инструменты» — Конфуций, «Аналитики Конфуция. Лу Лингун»
титульная страница > программирование > Создание умного редактора: автоматическое определение URL-адресов и преобразование их в гиперссылки

Создание умного редактора: автоматическое определение URL-адресов и преобразование их в гиперссылки

Опубликовано 4 ноября 2024 г.
Просматривать:265

Это идея, которая пришла мне в голову на работе, чтобы улучшить взаимодействие с пользователем. Он включает в себя реализацию текстового поля, которое автоматически обнаруживает URL-адреса и преобразует их в гиперссылки по мере ввода пользователем (исходный код Github/AutolinkEditor). Эту замечательную функцию довольно сложно реализовать, и необходимо решить следующие проблемы.

  • Точно определять URL-адреса в тексте
  • Сохранять положение курсора после преобразования строки URL в гиперссылку
  • Обновите целевой URL соответствующим образом, когда пользователи редактируют текст гиперссылки
  • Сохранять разрывы строк в тексте
  • Поддержка вставки форматированного текста с сохранением как текста, так и разрывов строк, при этом стиль текста соответствует формату текстового поля.

Building a Smart Editor: Automatically Detect URLs and Convert Them to Hyperlinks

...
 if(target && target.contentEditable){
  ...
  target.contentEditable = true;
  target.focus();
 }
...

Преобразование управляется событиями onkeyup и onpaste. Чтобы уменьшить частоту преобразований, реализован механизм задержки с помощью «setTimeout», где логика преобразования срабатывает только после того, как пользователь перестает печатать в течение 1 секунды по умолчанию.

idle(func, delay = 1000) {
      ...
      const idleHandler = function(...args) {
        if(this[timer]){
          clearTimeout(this[timer]);
          this[timer] = null;
        }
        this[timer] = setTimeout(() => {
          func(...args);
          this[timer] = null;
        }, delay);

      };
      return idleHandler.bind(this);
    }

Идентифицировать и извлекать URL-адреса с помощью регулярных выражений

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

...
const URLRegex = /^(https?:\/\/(([a-zA-Z0-9] -?) [a-zA-Z0-9] \.) (([a-zA-Z0-9] -?) [a-zA-Z0-9] ))(:\d )?(\/.*)?(\?.*)?(#.*)?$/;
const URLInTextRegex = /(https?:\/\/(([a-zA-Z0-9] -?) [a-zA-Z0-9] \.) (([a-zA-Z0-9] -?) [a-zA-Z0-9] ))(:\d )?(\/.*)?(\?.*)?(#.*)?/;
...

if(URLRegex.test(text)){
  result  = `${escapeHtml(text)}`;
}else {
  // text contains url
  let textContent = text;
  let match;
  while ((match = URLInTextRegex.exec(textContent)) !== null) {
    const url = match[0];
    const beforeUrl = textContent.slice(0, match.index);
    const afterUrl = textContent.slice(match.index   url.length);

    result  = escapeHtml(beforeUrl);
    result  = `${escapeHtml(url)}`;
    textContent = afterUrl;
  }
  result  = escapeHtml(textContent); // Append any remaining text
}

Восстановление позиции курсора после конвертации

С помощью функций document.createRange и window.getSelection рассчитайте положение курсора в тексте узла. Поскольку преобразование URL-адресов в гиперссылки только добавляет теги без изменения текстового содержимого, курсор можно восстановить на основе ранее записанной позиции. Для получения более подробной информации прочтите статью «Невозможно восстановить выделение после изменения HTML, даже если это тот же HTML».

Обновить или удалить при редактировании гиперссылки
Иногда мы создаем гиперссылки, в которых текст и целевой URL совпадают (здесь они называются «простыми гиперссылками»). Например, следующий HTML-код показывает гиперссылку такого типа.

http://www.example.com
Для таких ссылок при изменении текста гиперссылки целевой URL-адрес также должен автоматически обновляться, чтобы обеспечить их синхронизацию. Чтобы сделать логику более надежной, ссылка будет преобразована обратно в обычный текст, когда текст гиперссылки перестанет быть действительным URL-адресом.

handleAnchor: anchor => {
  ...
    const text = anchor.textContent;
    if(URLRegex.test(text)){
      return nodeHandler.makePlainAnchor(anchor);
    }else {
      return anchor.textContent;
    }
  ...
}
...
makePlainAnchor: target => {
  ...
  const result = document.createElement("a");
  result.href = target.href;
  result.textContent = target.textContent;
  return result;
  ...
}

Чтобы реализовать эту функцию, я сохраняю «простые гиперссылки» в объекте и обновляю их в режиме реального времени во время событий onpaste, onkeyup и onfocus, чтобы гарантировать, что приведенная выше логика обрабатывает только простые гиперссылки.

target.onpaste = initializer.idle(e => {
  ...
  inclusion = contentConvertor.indexAnchors(target);
}, 0);

const handleKeyup = initializer.idle(e => {
  ...
  inclusion = contentConvertor.indexAnchors(target);
  ...
}, 1000);

target.onkeyup = handleKeyup;
target.onfocus = e => {
  inclusion = contentConvertor.indexAnchors(target);
}

...

indexAnchors(target) {
  const inclusion = {};
  ...
  const anchorTags = target.querySelectorAll('a');
  if(anchorTags) {
    const idPrefix = target.id === "" ? target.dataset.id : target.id;

    anchorTags.forEach((anchor, index) => {
      const anchorId = anchor.dataset.id ?? `${idPrefix}-anchor-${index}`;
      if(anchor.href.replace(/\/ $/, '').toLowerCase() === anchor.textContent.toLowerCase()) {
        if(!anchor.dataset.id){
          anchor.setAttribute('data-id', anchorId);
        }
        inclusion[[anchorId]] = anchor.href;
      }
    });
  }
  return Object.keys(inclusion).length === 0 ? null : inclusion;
  ...
}

Обработка разрывов строк и стилей

При обработке вставленного форматированного текста редактор автоматически стилизует текст с помощью текстовых стилей редактора. Для сохранения форматирования теги
в форматированном тексте и все гиперссылки будут сохранены. Обработка входного текста более сложна. Когда пользователь нажимает Enter, чтобы добавить новую строку, в редактор добавляется элемент div, который редактор заменяет на
для сохранения форматирования.

node.childNodes.forEach(child => {
  if (child.nodeType === 1) { 
    if(child.tagName === 'A') { // anchar element
      const key = child.id === "" ? child.dataset.id : child.id;

      if(inclusion && inclusion[key]){
        const disposedAnchor = handleAnchor(child);
        if(disposedAnchor){
          if(disposedAnchor instanceof HTMLAnchorElement) {
            disposedAnchor.href = disposedAnchor.textContent;
          }
          result  = disposedAnchor.outerHTML ?? disposedAnchor;
        }
      }else {
        result  = makePlainAnchor(child)?.outerHTML ?? "";
      }
    }else { 
      result  = compensateBR(child)   this.extractTextAndAnchor(child, inclusion, nodeHandler);
    }
  } 
});

...
const ElementsOfBR = new Set([
  'block',
  'block flex',
  'block flow',
  'block flow-root',
  'block grid',
  'list-item',
]);
compensateBR: target => {
  if(target && 
    (target instanceof HTMLBRElement || ElementsOfBR.has(window.getComputedStyle(target).display))){
      return "
"; } return ""; }

Выводы

В этой статье описаны некоторые практические методы, используемые для реализации простого редактора, такие как общие события, такие как onkeyup и onpaste, как использовать Selection и Range для восстановления положения курсора и как обрабатывать узлы элемента для достижения редактора. функциональность. Хотя регулярные выражения не являются предметом этой статьи, полное регулярное выражение может повысить надежность редактора при идентификации конкретных строк (регулярное выражение, используемое в этой статье, останется открытым для изменения). Вы можете получить доступ к исходному коду через Github/AutolinkEditor, чтобы получить более подробную информацию, если это полезно для вашего проекта.

Заявление о выпуске Эта статья воспроизведена по адресу: https://dev.to/oninebx/building-a-smart-editor-automatically-detect-urls-and-convert-them-to-hyperlinks-ilg?1 Если есть какие-либо нарушения, пожалуйста, свяжитесь с Study_golang@163 .comdelete
Последний учебник Более>

Изучайте китайский

Отказ от ответственности: Все предоставленные ресурсы частично взяты из Интернета. В случае нарушения ваших авторских прав или других прав и интересов, пожалуйста, объясните подробные причины и предоставьте доказательства авторских прав или прав и интересов, а затем отправьте их по электронной почте: [email protected]. Мы сделаем это за вас как можно скорее.

Copyright© 2022 湘ICP备2022001581号-3