티스토리 뷰

카테고리 없음

보투게더 사용성 개선하기 (2) - 게시글, 댓글 작성 시 링크 첨부

YG - 96년생 , 강아지 있음, 개발자 희망 2023. 10. 24. 12:19

보투게더 팀 블로그에서 작성한 글을 가져왔습니다.

 

보투게더 사용성 개선하기 (2) - 게시글, 댓글 작성 시 링크 첨부

게시글, 댓글의 경우에 링크 넣기 버튼을 눌른 후 \[ ] 사이에 사용자가 직접 괄호 사이에 링크를 넣고 저장 버튼을 눌러야 했습니다. 그러나 게시글이나 댓글 기능을 사용하면서 링크 첨부를 하

velog.io

 

 

문제점

  1. 게시글, 댓글의 경우에 링크 넣기 버튼을 누른 후 [[ ]] 사이에 사용자가 직접 괄호 사이에 링크를 넣고 저장 버튼을 눌러야 했습니다. 그러나 게시글이나 댓글 기능을 사용하면서 링크 첨부를 하는 방식이 불편하다고 느꼈습니다.

해결 방법

  1. 본문 링크 삽입 시 [[ ]] 을 붙여주고 있는데, 이걸 작성자에게 붙이도록 하지 않고 렌더링 시 http | https | www로 시작하는 문자를 정규표현식을 이용하여 [[ 주소 ]]를 붙여주도록 함
  2. 이때 기존의 사용되던 [[ 링크 ]] 텍스트가 있다면 변환되지 않도록 하였음

구현 방법

  1. 정규식을 이용하여 https로 시작하는 문자가 있는지 확인하여 변환합니다.
  2. https가 변환된 문자 중 www로 시작하는 문자가 있는지 확인하여 변환합니다.
  3. 이때 [[ ]]로 감싸져 있는 문자는 변환하지 않습니다.

convertTextToUrl.ts

/**
 * https://abc.co.kr/@abc/4
 * https://votogether.com/
 * http://localhost:3000/posts/100035
 * http://votogether.com/
 * (?
const httpsOrHttpRegex = /(?<!\[\[)(https?:\/\/[^\s]+)(?!\]\])/g;

/**
 * www.naver.com
 * www.tistory.com
 * (?<!\[\[) 는 앞에 [[로 시작하는 지 여부를 확인한다
 * (?<!\/)는 앞에 /로 시작하는 지 여부를 확인한다. https://www 에서 www 앞에 /가 있기에 중복되어 확인하는 것을 방지하기 위함
 * \b(w{3})\b 는 www로 시작하는 지 여부를 정확히 확인한다. w가 4개인 경우 판별하지 않음
 * [^\s] 는 공백이 아닌 문자인지 여부를 확인한다.
 * (?!\]\]) 는 뒤에 ]]로 끝나는 지 여부를 확인한다.
 */
const wwwRegex = /(?<!\[\[)(?<!\/)\b(w{3})\b[^\s]+(?!\]\])/g;

export const convertTextToUrl = (text: string) => {
  const httpOrHttpsConvertedText = text.replace(httpsOrHttpRegex, url => `[[${url}]]`);
  const wwwConvertedText = httpOrHttpsConvertedText.replace(wwwRegex, url => `[[${url}]]`);

  return wwwConvertedText;
};

convertTextToUrl.test.ts

import { convertTextToUrl } from '@utils/post/convertTextToUrl';

test.each([
  ['www.naver.com 이걸 어째', '[[www.naver.com]] 이걸 어째'],
  [
    '반갑다 https://github.com/woowacourse-teams/2023-votogether/issues/703    임',
    '반갑다 [[https://github.com/woowacourse-teams/2023-votogether/issues/703]]    임',
  ],
  ['안녕 wwwww.naver.com', '안녕 wwwww.naver.com'],
  ['http://localhost:3000/ 피카츄', '[[http://localhost:3000/]] 피카츄'],
  [
    'http://localhost:3000/http://localhost:3000/ 피카츄',
    '[[http://localhost:3000/http://localhost:3000/]] 피카츄',
  ],
  ['www.naver.com', '[[www.naver.com]]'],
  ['[[www.naver.com]] www.naver.com', '[[www.naver.com]] [[www.naver.com]]'],
  [
    '[[http://localhost:3000/]] http://localhost:3000/',
    '[[http://localhost:3000/]] [[http://localhost:3000/]]',
  ],
  [
    '[[https://votogether.com/ranking]] https://www.naver.com/',
    '[[https://votogether.com/ranking]] [[https://www.naver.com/]]',
  ],
  [
    'www.naver.com www.naver.com www.naver.com https://www.npmjs.com/package/dotenv-webpack',
    '[[www.naver.com]] [[www.naver.com]] [[www.naver.com]] [[https://www.npmjs.com/package/dotenv-webpack]]',
  ],
])(
  'convertTextToUrl 함수에서 링크가 포함된 문자를 입력했을 때 문자에서 링크는 [[]]로 감싸서 반환한다.',
  (word, expectedWord) => {
    const result = convertTextToUrl(word);

    expect(result).toBe(expectedWord);
  }
);

사용 예시

  1. [[ ]] 로 감싼 문자가 있는지 정규식으로 확인하여 split 해줍니다.
  2. [[ ]] 를 기준으로 split 하게 되면 괄호는 사라지고 링크 내용만 남게 되고, index % 2 === 1이 링크 내용이 됩니다.
  3. 링크 내용이라면 a 태그로 반환하고, 아니라면 span으로 반환합니다.

convertTextToElement.tsx

import { MouseEvent } from 'react';

import { convertTextToUrl } from './convertTextToUrl';

export const convertTextToElement = (text: string) => {
  const convertedUrlText = convertTextToUrl(text);
  const linkPattern = /\[\[([^[\]]+)\]\]/g;

  const parts = convertedUrlText.split(linkPattern);

  const elementList = parts.map((part, index) => {
    if (index % 2 === 1) {
      // 링크
      const linkText = part;
      const linkUrl = linkText.startsWith('http' || 'https') ? linkText : `https://${linkText}`;
      return (
        <a
          onClick={(event: MouseEvent<HTMLAnchorElement>) => {
            event.stopPropagation();
          }}
          key={index}
          href={linkUrl}
          target="_blank"
          style={{ textDecoration: 'underline', color: '#004EC5' }}
          rel="noreferrer noopener"
        >
          {linkText}
        </a>
      );
    }

    // 링크가 아닌 문자열
    return <span key={index}>{part}</span>;
  });

  return elementList;
};

본문을 변환해 줘서 사용

  <S.Content>
   {convertTextToElement(content)}
  </S.Content>

링크 첨부하는 영상

 

댓글 링크 첨부

 

🚨 safari 에러 발생 🚨

 

? <와 같은 문법을 safari에서는 최근에서야 지원을 하기 시작해서 업데이트를 하지 않은 safari에서는 사이트가 보이지 않게 됩니다.

 

 

 

safari 브라우저 정규표현식 Invalid regular expression 에러 처리

safari 브라우저에서 발생한 Invalid regular expression 에러 기록

se9round.dev

 

 

 

Lookbehind in JS regular expressions | Can I use... Support tables for HTML5, CSS3, etc

The positive lookbehind ((?<= )) and negative lookbehind ((?<! )) zero-width assertions in JavaScript regular expressions can be used to ensure a pattern is preceded by another pattern.

caniuse.com

 

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함