부호 편집기에 붙여넣기 시 클립보드 데이터의 `white-space` CSS 속성이 반영되지 않음

우선순위/심각도:

중간

플랫폼:

운영체제

  • Windows 11

브라우저

  • Google Chrome 139.0.7258.128

Discourse

028c90dd5e7a2799ea5b6e963f71fc0222681943

설명:

일부 출처에서 복사한 텍스트는 일반 텍스트(text/plain) 외에도 서식이 적용된 형태(text/html 유형)로 클립보드에 저장될 수 있습니다.

편집기에 텍스트를 붙여넣을 때, 클립보드에 서식이 적용된 데이터 유형이 존재하면 일반 텍스트 유형 대신 해당 데이터가 사용됩니다.

기본적으로 HTML 콘텐츠의 공백은 축소됩니다. 이 동작은 white-space CSS 속성을 통해 제어할 수 있습니다.

:bug: “리치 텍스트 에디터” 모드에서 편집기에 붙여넣을 때, 클립보드 데이터의 white-space CSS 속성이 무시됩니다. 이로 인해 붙여넣은 콘텐츠의 공백이 항상 축소됩니다. 원본 콘텐츠에 white-space 속성이 pre 값으로 설정되어 있는 경우, 붙여넣은 콘텐츠가 읽기 어렵게 되며, 원본 콘텐츠의 공백이 기술적 의미를 가지는 경우 오류가 발생합니다.

재현 단계:

  1. 다음 내용을 가진 HTML 파일을 생성합니다:
    <html>
      <body>
        <span style="white-space: pre">foo
    bar
        </span>
      </body>
    </html>
    
  2. 웹 브라우저에서 파일을 엽니다.
    페이지 콘텐츠의 공백이 축소되지 않음을 확인하세요:
    foo
    bar
    
  3. 웹 페이지의 내용을 복사합니다.
  4. 게시글 편집기를 엽니다.
  5. 편집기를 “리치 텍스트 에디터” 모드로 설정합니다.
  6. 복사한 내용을 붙여넣습니다.

:bug: 복사된 콘텐츠와 동일한 형식이 아니라, 붙여넣은 콘텐츠의 공백이 축소되었습니다:

foo bar

추가 정보:

ProseMirror가 white-space: pre를 지원함을 확인했습니다:


편집기를 “Markdown 에디터” 모드로 사용할 때 이 오류는 발생하지 않습니다.


일반적인 에디터 모드 대신 코드 블록에 콘텐츠를 붙여넣을 경우에도 이 오류는 발생하지 않습니다. white-space: pre와 같은 것을 사용하는 콘텐츠를 코드 블록에 배치하는 것이 가장 적절할 수 있는 경우가 많긴 합니다. 그러나 사용자가 편집기에 콘텐츠를 추가한 후, 콘텐츠를 선택하고 편집기 툴바를 사용하여 서식을 적용하는 방식으로 사후에 서식을 적용하는 것이 상당히 흔합니다(콘텐츠를 추가하기 전에 코드 블록을 트리거하는 대안적 접근 방식과 반대되는 경우).


클립보드 콘텐츠의 원시 데이터를 조사하는 데 유용한 도구를 찾았습니다:


try.discourse.org"안전 모드"에서 이 오류를 재현할 수 있습니다.

관련

2개의 좋아요

웹 페이지에서 복사한 내용을 붙여넣기 전에 게시글 작성기를 “리치 텍스트 에디터” 모드로 설정했나요?

여전히 오류가 발생합니다.

설명서에 적힌 대로 정확히 따랐는지 확인해 주셨나요?

해당 HTML에서 렌더링된 내용을 복사해야 클립보드에 text/html 형식의 데이터가 채워진다는 점을 유의해 주세요:

<html>
<body>
<!--StartFragment--><span style="color: rgb(0, 0, 0); font-family: &quot;Times New Roman&quot;; font-size: medium; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: pre; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial; display: inline !important; float: none;">foo
bar
    </span><!--EndFragment-->
</body>
</html>

이는 HTML 마크업을 사용하여 게시글을 작성하라는 의미가 아닙니다.

아, 좋은 지적이에요. 저는 가끔 글을 너무 빨리 훑어보는 경향이 있거든요 :sweat_smile:

1개의 좋아요

@per1234 님, 보고해 주셔서 감사합니다. 현재 확인 중입니다.

여기서 일반적인 문제를 이해하고 있으며, 사람들이 코드 예제를 붙여 넣을 때 최대한 간편할 수 있도록 하고 싶습니다.

2개의 좋아요

이런 HTML 클립보드에서 어떤 결과가 나올 것 같으신가요?

foo
bar

아니면, span 태그이므로 두 줄의 인라인 코드 사이에 하드 브레이크가 있는 형태일까요?

foo
bar

아니면 줄바꿈은 존중하되, 일반 문단 안에서 하드 브레이크가 있는 형태일까요?

foo
bar

감사합니다!

HTML에 대해 아주 잘 아는 것은 아니지만, 이 렌더링을 기대합니다:

제 판단으로는 Chrome 브라우저가 이렇게 렌더링하는 것 같습니다.


그럼에도 불구하고, 제가 문제를 겪었던 특정 사용 사례에서는 코드 블록 렌더링이 가장 적절하다는 것이 사실입니다. "Arduino Cloud Editor

1개의 좋아요

이 경우에도 클립보드의 text/html 출력에 span 태그를 사용하는지, 아니면 plain/text만 출력하는 것인가요?

Arduino Cloud Editor의 “Copy Console Output” 버튼을 클릭한 후 클립보드에 어떤 데이터가 있는지 확인하기 위해 “Clipboard Inspector” 도구를 사용해 보았더니, 다음과 같은 “text/plain” 형식의 데이터가 포함되어 있는 것을 확인할 수 있었습니다:

/run/arduino/sketches/asdf/asdf.ino:1:2: error: #error foo
 #error foo
  ^~~~~

또한, 다음과 같은 “text/html” 형식의 데이터도 포함되어 있었습니다:

<span style="color: rgb(0, 0, 0); font-family: &quot;Open Sans&quot;, &quot;Lucida Grande&quot;, lucida, verdana, sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: 0.16px; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: pre; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial; display: inline !important; float: none;">/run/arduino/sketches/asdf/asdf.ino:1:2: error: #error foo
 #error foo
  ^~~~~</span>

이 답변이 도움이 되길 바랍니다. 추가로 필요한 정보가 있다면 기꺼이 제공하겠습니다.

이 문제는 FIX: [rich editor] convert newlines to hard breaks when parsed from HTML - Pull Request #35518 - discourse/discourse - GitHub (아직 병합되지 않았으며, 코드 리뷰를 기다리고 있음)에서 수정될 예정입니다.

첫 번째 시도는 이를 코드 블록으로 변환하는 것이었지만, 그렇게 하면 지나치게 공격적(false positive)인 결과를 초래할 수 있다고 생각합니다. 대신, HTML이 붙여넣어진 컨텍스트 내에서 줄바꿈을 하드 브레이크로 변환하여 이를 존중하도록 했습니다. (ProseMirror의 prosemirror-model에 대한 Marijn의 개선 사항에 감사드립니다: When preserving whitespace, replace newlines with line break replacem… · ProseMirror/prosemirror-model@79e9f2b · GitHub)

최근 코드 도구 모음 버튼의 개선 사항 덕분에, 사용자는 하드 브레이크가 포함된 이 붙여넣은 섹션을 선택하여 코드 블록으로 변환할 수 있으며, 줄바꿈도 그대로 유지됩니다.

2개의 좋아요

수정해 주셔서 정말 감사합니다, @renato. 여기에 업데이트를 게시해 주신 시간까지 감사드립니다!

최근 버그 수정으로 인해 리치 텍스트 편집기의 기능이 비기술적 사용자에게 접근성을 높이는 수준까지 향상되었습니다. 이들은 마크다운에 이미 익숙하지 않으며, 마크다운을 배우려는 동기도 없습니다.


아직도 결과가 기대와 다르게 나타나는 몇 가지 조건이 있지만, 이는 Discourse 코드베이스를 통해 합리적으로 완화할 수 있는 사항들이 아닙니다:

우발적인 마크업 문법으로 인한 손상

내용이 우연히 마크업과 유사한 경우 게시물이 손상될 수 있습니다. 이는 리치 텍스트 편집기에서 마크업을 지원하도록 의도적으로 결정했기 때문입니다.

마크다운 편집기를 사용하려는 사용자는 마크다운 편집기를 사용하고, 리치 텍스트 편집기는 마크업 사용에 관심이 없는 사용자만을 위해 제공되는 우리의 사용 사례에서, 이는 매우 불행한 결정입니다. 비기술적 사용자가 마크다운 편집기를 사용할 때 우발적인 마크업으로 인한 게시물 손상은 우리가 직면한 가장 심각한 문제 중 하나였으며, 리치 텍스트 편집기가 이를 해결해 줄 것으로 큰 희망을 걸었습니다. 그러나 포럼이 리치 텍스트 편집기만 제공하는 사용 사례에서는, 이 설계는 마크다운에 능숙한 사용자가 여전히 효율적으로 게시물을 작성할 수 있게 해주므로 완벽하게 타당합니다.

클립보드 내용의 부적절한 마크업으로 인한 잘못된 서식

특정 애플리케이션에서 복사할 때 클립보드에 추가되는 “text/html” 타입의 내용에 부적절한 HTML 마크업이 포함되어 있어, 코드 블록 외부의 리치 텍스트 편집기에 붙여넣을 때 서식이 잘못 적용되는 사례가 있습니다.

이것은 물론 해당 애플리케이션의 버그이며, Discourse는 마크업이 지시한 대로 내용을 서식화함으로써 100% 올바르게 작동하고 있습니다.

1개의 좋아요

@per1234 감사합니다!

부패(corruption)가 발생할 수 있는 예시에 대해 조금 더 자세히 설명해 주실 수 있을까요? 렌더링할 방법을 모르는 노드(node)에 대한 몇 가지 엣지 케이스가 여전히 남아 있지만, 이러한 경우에서 리치 에디터로 전환하는 것을 금지하려고 노력하고 있습니다.

클립보드와 관련하여, 우리는 확실히 개선하고 싶습니다. 이는 어려운 문제이며, 여기에 정확한 재현 단계를 공유해 주시면 매우 도움이 될 것입니다.

물론입니다. 이 정보가 도움이 되길 바랍니다. 이전 제 발언을 다시 한 번 강조하고 싶습니다:

다만, 제 생각이 틀렸을 수도 있습니다 :slightly_smiling_face:.

  1. 다음 C++ 코드를 복사하세요:
    #include <iostream>
    int main() {
      std::cout << __FILE__;
    }
    
  2. 게시물 작성기를 열립니다.
  3. 작성기를 “리치 텍스트 에디터” 모드로 설정합니다.
  4. 복사한 내용을 작성기에 붙여넣습니다.

:slightly_frowning_face: 내용이 손상됩니다:

#include
int main() {
std::cout << FILE;
}

(<iostream>이 지원되지 않는 HTML 태그와 유사하여 제거되었고, __FILE__가 굵은 글씨 마크업으로 처리되었음을 유의하세요)

이것은 비프로즈(non-prose) 내용을 붙여넣기 전에 코드 블록을 트리거하면 피할 수 있으므로 사용자 오류로 볼 수도 있습니다. 그러나 붙여넣은 내용에 사후적으로 코드 블록 서식을 적용하는 대안 워크플로우도 동등하게 유효해야 한다고 기대할 수 있습니다(Markdown 에디터 사용 시와 같이).

장비

  • Arduino 보드 (공식 제품 또는 3rd party 제품)

설명

  1. Arduino 웹사이트 “Software” 페이지에서 다운로드할 수 있는 Arduino IDE 2.3.6을 설치하세요:
    https://www.arduino.cc/en/software/#ide-download-section
  2. Arduino IDE를 시작합니다.
  3. Arduino IDE 메뉴에서 File > New Sketch를 선택합니다.
  4. 새 스케치의 내용을 다음 코드로 교체합니다:
    void setup() {
      Serial.begin(9600);
      while (!Serial) {}  // Wait for serial port to be opened.
      delay(500);         // Some boards require a delay after serial port initialization.
      Serial.println("foo");
      Serial.println("bar");
    }
    void loop() {}
    
  5. Arduino IDE 메뉴에서 Tools > Serial Monitor를 선택하여 Serial Monitor 뷰를 엽니다(이미 열려 있지 않은 경우).
  6. Serial Monitor 뷰의 보드레이트 메뉴에서 "9600"을 선택합니다.
  7. 스케치를 Arduino 보드에 업로드합니다.
  8. Serial Monitor 뷰의 필드에서 시리얼 출력을 선택합니다.
  9. 선택된 내용을 복사합니다.
  10. Discourse 게시물 작성기를 엽니다.
  11. 작성기를 “리치 텍스트 에디터” 모드로 설정합니다.
  12. 복사한 내용을 작성기에 붙여넣습니다.

:slightly_frowning_face: 복사된 내용의 각 줄이 별도의 코드 블록에 배치됩니다:

foo

bar

클립보드 내용을 검사하면, 예상되는 “text/plain” 유형 내용 외에:

foo
bar

다음과 같은 “text/html” 유형 내용도 포함되어 있음을 볼 수 있습니다:

<div style="color: rgb(78, 91, 97); font-family: monospace; font-size: 13px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: nowrap; background-color: rgb(255, 255, 255); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial; position: absolute; left: 0px; top: 0px; height: 18px; width: 1862px;"><pre style="margin: 0px;">foo
</pre></div><div style="color: rgb(78, 91, 97); font-family: monospace; font-size: 13px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: nowrap; background-color: rgb(255, 255, 255); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial; position: absolute; left: 0px; top: 18px; height: 18px; width: 1862px;"><pre style="margin: 0px;">bar</pre></div>

Arduino IDE 2.x Serial Monitor가 복사된 “text/html” 유형 내용의 각 줄을 <pre> 태그로 잘못 감싸기 때문에, Discourse 리치 텍스트 에디터가 붙여넣은 내용의 각 줄을 별도의 코드 블록으로 렌더링하는 것은 정확하고 예상된 동작입니다.

위에서 설명한 다른 문제와 마찬가지로, 내용을 붙여넣기 전에 선제적으로 코드 블록 서식을 트리거하면 예상치 못한 서식 문제를 피할 수 있습니다.

2개의 좋아요

붙여넣은 일반 텍스트를 마크다운으로 파싱하는 것은 예상되는 동작이며, 그렇게 하지 않으면 사용자 경험이 더 나빠진다고 생각합니다(제 의견). 하지만 실질적인 제안은 환영합니다. 마크다운으로 파싱하지 않고 붙여넣는 기능을 위해 SHIFT 수정키를 지원하는 것이 도움이 될까요?

이것은 변경할 수 있으며, 하나의 가능성은 제거하는 대신 \<iostream\>로 이스케이프 처리하는 것입니다.


말씀하신 다른 지점은 조치할 사항이 아닌 것 같습니다.

이 주제와 관련하여 여전히 어려움을 겪고 있는 부분이 더 있으신가요?

이 주제는 64일 후 자동으로 닫혔습니다. 더 이상 새 답변을 작성할 수 없습니다.