リッチテキストエディタに貼り付ける際にクリップボードデータの`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. Webブラウザでファイルを開きます。
    ページコンテンツの空白が折りたたまれていないことに注意してください。
    foo
    bar
    
  3. Webページのコンテンツをコピーします。
  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>foo
bar
    </span><!--EndFragment-->
</body>
</html>

これは、HTMLマークアップを使用して投稿を作成することではありません。

よく気づきましたね。投稿を速すぎるところまで読み飛ばしてしまう傾向があります :sweat_smile:

「いいね!」 1

ご報告ありがとうございます @per1234、確認しています。

一般的な問題として、コード例を簡単に貼り付けられるようにしたいと考えています。

「いいね!」 2

このようなHTMLクリップボードからは何が期待できますか?

foo
bar

または、spanタグであることを考慮して、間にハードブレークを挟んだ2つのインラインコード行ですか?

foo
bar

または、単に改行を尊重し、ハードブレークを挟んだ通常の段落として表示されるのでしょうか?

foo
bar

ありがとうございます!

HTMLについてはあまり詳しくありませんが、次のような表示になると予想します。

私の知る限り、Chromeブラウザはこれをこのように表示します。


とはいえ、私が問題に遭遇した特定の用途では、コードブロックの表示が最も適切であることは確かです。この種のクリップボードコンテンツは、「Arduino Cloud Editor」というオンラインIDEの「Copy Console Output」ボタンをクリックすることで取得できます。

これにより、コンパイラやその他のツールによって生成された出力がクリップボードにコピーされます。この種の非文章コンテンツは、コードブロックとしてフォーマットするのが最適です。

フォーラム投稿でコピーした出力を共有するために、次の手順を使用した場合:

  1. ポストコンポーザーを「リッチテキストエディタ」モードにします。
  2. コンポーザーにコンテンツを貼り付けます。
  3. 貼り付けたコンテンツを選択します。
  4. コンポーザーツールバーの「</>」アイコンをクリックします。

投稿は次のようなフォーマットになります。

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

(コピーされたコンテンツはすべて1行にあることに注意してください)

しかし、次のような投稿フォーマットを期待します。

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

ただし、コードブロックに対するこの好みは、特定のユースケースに限定されます。他のユースケースでは、white-space: pre プロパティを持つクリップボードコンテンツのソースがあり、コードブロックが適切でない場合があるかもしれません。また、私たちのユースケースであっても、ユーザーにコードブロックフォーマットを手動で適用する責任を負わせるのは合理的です。

「いいね!」 1

もうそうではありません。これは最近修正されました(ここでテストできます)。

この場合、text/html クリップボード出力で span タグが引き続き使用されますか、それとも plain/text のみが出力されますか?

the “Clipboard Inspector” tool を使用して、Arduino Cloud Editor の「Copy Console Output」ボタンをクリックした後にクリップボードにどのようなデータがあるかを確認すると、次の「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 by renato · Pull Request #35518 · discourse/discourse · GitHub (まだマージされておらず、コードレビュー待ちです) で修正されるはずです。

私の最初の試み (first take) は、コードブロックに変換することでしたが、それは早計すぎで誤検出を引き起こす可能性があると考えました。代わりに、HTML が貼り付けられたコンテキスト内で改行を尊重し、ハードブレークに変換します。(Marijn による prosemirror-model の改善: When preserving whitespace, replace newlines with line break replacem… · ProseMirror/prosemirror-model@79e9f2b · GitHub に感謝します)

コードツールバーボタンの最近の改善により、ユーザーはハードブレークを含むこの貼り付けられたセクションを選択してコードブロックに変換できるようになり、改行も引き継がれるはずです。

「いいね!」 2

@renato、修正ありがとうございます。また、こちらにアップデートを投稿するお時間をいただき感謝いたします。

最近のバグ修正により、リッチテキストエディタの機能は、Markdownに慣れていない、または学習意欲のない、技術に詳しくないユーザーにとって、私たちのフォーラムをより親しみやすいものにするのに役立つレベルに達しました。


まだ予期しない結果が生じる条件がいくつかありますが、これらはDiscourseのコードベースで軽減することが合理的ではないものです。

マークアップ構文の偶然の一致による破損

マークアップに偶然似ているコンテンツがある場合、投稿が破損する可能性があります。これは、リッチテキストエディタでのマークアップのサポートという意図的な決定によるものです。

マークアップを使用したいユーザーはMarkdownエディタを使用し、リッチテキストエディタはマークアップの使用に興味のないユーザーのみを対象とするという私たちのユースケースでは、これは非常に残念な決定です。非技術ユーザーがMarkdownエディタを使用する際に最も大きな問題の1つは、偶然のマークアップによる投稿の破損であり、リッチテキストエディタがその解決策を提供してくれることを大いに期待していました。しかし、フォーラムがリッチテキストエディタのみを提供するユースケースでは、Markdownに精通したユーザーが効率的に投稿を作成できるため、この設計は完全に理にかなっています。

クリップボードコンテンツの不適切なマークアップによるフォーマットの誤り

特定のアプリケーションからコピーする際にクリップボードに追加される「text/html」タイプのコンテンツに不適切なHTMLマークアップが含まれており、コードブロック外のリッチテキストエディタに貼り付けるとフォーマットが誤るというケースがあります。

これはもちろんアプリケーションのバグであり、マークアップで示されたとおりにコンテンツをフォーマットしているDiscourseは100%正しく動作しています。

「いいね!」 1

@per1234 さん、ありがとうございます。

破損が発生する可能性のある例について、もう少し詳しく説明していただけますか?ノードのレンダリング方法が不明なエッジケースがいくつか残っていますが、このような場合にリッチエディターへの切り替えを禁止するようにしています。

クリップボードに関しては、改善したいと考えていることは確かです。これは難しい問題であり、正確な再現手順があれば非常に役立ちます。

はい。情報がお役に立てば幸いです。以前の発言を繰り返したいと思います。

しかし、もし私が間違っていたら喜んで訂正します :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__ は太字マークアップとして扱われています)

これはユーザーエラーと見なされる可能性があります。なぜなら、プロセではないコンテンツを貼り付ける前にコードブロックをトリガーすることで回避できるからです。しかし、貼り付けたコンテンツに後からコードブロックフォーマットを適用するという代替ワークフローも同様に有効であると期待できるかもしれません(Markdownエディターを使用する場合と同様です)。

機器

  • 公式またはサードパーティのいずれかの Arduino ボード

手順

  1. Arduino Web サイトの「ソフトウェア」ページからダウンロードできる 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) {}  // シリアルポートが開くまで待機します。
      delay(500);         // 一部のボードでは、シリアルポート初期化後に遅延が必要です。
      Serial.println("foo");
      Serial.println("bar");
    }
    void loop() {}
    
  5. Arduino ボードにスケッチをアップロードします。
  6. Arduino IDE メニューから Tools > Serial Monitor を選択して、まだ開いていない場合は Serial Monitor ビューを開きます。
  7. Serial Monitor ビューのボーレートメニューから「9600」を選択します。
  8. Arduino ボードにスケッチをアップロードします。
  9. Serial Monitor ビューのフィールドからシリアル出力を選択します。
  10. 選択したコンテンツをコピーします。
  11. Discourse ポストコンポーザーを開きます。
  12. コンポーザーを「リッチテキストエディター」モードにします。
  13. コピーしたコンテンツをコンポーザーに貼り付けます。

:slightly_frowning_face: コピーしたコンテンツの各行が個別のコードブロックに配置されます。

foo

bar


クリップボードコンテンツを検査すると、「text/plain」タイプのコンテンツに加えて、次の「text/html」タイプのコンテンツも含まれていることがわかります。

foo
bar
<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 のシリアルモニターは、「text/html」タイプのコピーされたコンテンツの各行を pre タグで誤ってラップするため、Discourse のリッチテキストエディターによって貼り付けられたコンテンツの各行が個別のコードブロックとしてレンダリングされるのは、正しく予期された動作です。

上記で説明した他の問題と同様に、予期しないフォーマットは、コンテンツを貼り付ける前にコードブロックフォーマットを積極的にトリガーすることで回避できます。

「いいね!」 2