خاصية `white-space` CSS لبيانات الحافظة لا يتم احترامها عند اللصق في محرر النصوص المنسقة

الأولوية/الخطورة:

متوسط

المنصة:

نظام التشغيل

  • ويندوز 11

المتصفح

  • جوجل كروم 139.0.7258.128

ديسكورس

028c90dd5e7a2799ea5b6e963f71fc0222681943

الوصف:

قد يتم تخزين النص المنسوخ من بعض المصادر في الحافظة بتنسيق (نوع text/html) بالإضافة إلى النص العادي (نوع text/plain).

عند لصق النص في المحرر، إذا كان نوع بيانات منسق موجودًا في الحافظة، فسيتم استخدام هذه البيانات بدلاً من نوع النص العادي.

افتراضيًا، يتم ضغط المسافات البيضاء في محتوى HTML. يمكن التحكم في هذا السلوك عبر خاصية CSS white-space.

:bug: عند اللصق في المحرر أثناء وجوده في وضع “محرر النص المنسق”، لا يتم احترام خاصية CSS white-space لبيانات الحافظة. ينتج عن هذا دائمًا ضغط المسافات البيضاء في المحتوى الملصق. في الحالات التي كانت فيها خاصية 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>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. ضع منشئ المنشور في وضع “محرر النصوص المنسقة”.
  2. الصق المحتوى في المنشئ.
  3. حدد المحتوى الملصق.
  4. انقر فوق الرمز </> الموجود على شريط أدوات المنشئ.

ينتهي المنشور بالتنسيق التالي:

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

(لاحظ أن كل المحتوى المنسوخ موجود في سطر واحد)

بينما نتوقع تنسيق المنشور هذا:

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

ومع ذلك، فإن هذا التفضيل لكتلة التعليمات البرمجية خاص بحالتنا المحددة. قد يكون أنه في حالات استخدام أخرى توجد مصادر لمحتوى الحافظة بخصائص white-space: pre والتي قد لا تكون كتلة التعليمات البرمجية مناسبة لها. وحتى في حالتنا، من المعقول وضع مسؤولية تطبيق تنسيق كتلة التعليمات البرمجية يدويًا على المستخدم.

إعجاب واحد (1)

لم يعد الأمر كذلك، فقد تم إصلاح هذا مؤخرًا (يمكنك اختباره هنا).

في هذه الحالة، هل لا يزال يستخدم علامة span في مخرجات الحافظة text/html الخاصة به، أم أنه يخرج plain/text فقط؟

إذا استخدمت أداة “Clipboard Inspector” للتحقق من البيانات الموجودة في الحافظة الخاصة بي بعد النقر على زر “Copy Console Output” في Arduino Cloud Editor، فسيظهر أن هناك بيانات من النوع “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 (لم يتم دمجه بعد، ولا يزال ينتظر مراجعة الكود).

كان أخذي الأول هو تحويله إلى كتلة كود، لكن أعتقد أن هذا سيكون متسرعًا جدًا وسيسبب بعض النتائج الإيجابية الخاطئة. بدلاً من ذلك، نحترم فواصل الأسطر فقط ونحولها إلى فواصل صلبة في سياق لصق HTML. (بفضل تحسينات Marijn على prosemirror-model: When preserving whitespace, replace newlines with line break replacem… · ProseMirror/prosemirror-model@79e9f2b · GitHub)

مع التحسينات الأخيرة على زر شريط أدوات الكود، يجب أن يكون المستخدمون قادرين على تحديد هذا القسم الملصق مع الفواصل الصلبة وتحويله إلى كتلة كود، ويجب نقل فواصل الأسطر.

إعجابَين (2)

شكراً جزيلاً على الإصلاح يا @renato، وعلى تخصيص الوقت لنشر تحديث هنا!

لقد جلبت إصلاحات الأخطاء الأخيرة وظائف محرر النصوص المنسقة إلى النقطة التي يمكن أن تجعل منتدانا أكثر سهولة للمستخدمين الأقل خبرة تقنية الذين ليسوا على دراية بالفعل بـ Markdown وغير متحمسين لتعلمه.


لا تزال هناك بعض الحالات التي تكون فيها النتائج غير متوقعة، ولكن هذه أمور غير معقولة للتخفيف منها عبر قاعدة كود Discourse:

تلف بسبب بناء جملة العلامات العرضي

قد تتلف المشاركات في حالة وجود محتوى يشبه العلامات عن طريق الصدفة. هذا يرجع إلى القرار المتعمد لدعم العلامات في محرر النصوص المنسقة.

بالنسبة لحالة الاستخدام الخاصة بنا حيث يُتوقع من أولئك الذين يرغبون في استخدام العلامات استخدام محرر Markdown، بينما يُقصد بمحرر النصوص المنسقة فقط للاستخدام من قبل أولئك الذين ليس لديهم اهتمام باستخدام العلامات، فهذا قرار مؤسف للغاية. إحدى أهم المشكلات التي نواجهها مع المستخدمين غير التقنيين الذين يستخدمون محرر Markdown هي تلف المشاركات بسبب العلامات العرضية، وكان لدي آمال كبيرة في أن يوفر محرر النصوص المنسقة حلاً لذلك. ومع ذلك، بالنسبة لحالة الاستخدام حيث سيوفر المنتدى محرر نصوص منسقة فقط، فإن هذا التصميم منطقي تمامًا لأنه لا يزال يسمح للمستخدمين الماهرين في 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;
}

(لاحظ أنه تم كتم \u003ciostream\u003e لأنه يشبه علامة HTML غير مدعومة، وتم التعامل مع __FILE__ كعلامة جريئة)

يمكن اعتبار هذا خطأ من المستخدم، حيث يمكن تجنبه عن طريق تشغيل كتلة الكود قبل لصق المحتوى غير النثري. ومع ذلك، قد نتوقع أن يكون سير العمل البديل المتمثل في تطبيق تنسيق كتلة الكود بأثر رجعي على المحتوى الملصق بنفس القدر من الصلاحية (كما هو الحال عند استخدام محرر Markdown).

المعدات

  • أي لوحة Arduino (سواء كانت رسمية أو من طرف ثالث)

التعليمات

  1. قم بتثبيت Arduino IDE 2.3.6، والتي يمكن تنزيلها من صفحة “البرامج” على موقع Arduino:
    https://www.arduino.cc/en/software/#ide-download-section
  2. ابدأ Arduino IDE.
  3. حدد File > New Sketch من قوائم Arduino IDE.
  4. استبدل محتوى الرسم التخطيطي الجديد بالكود التالي:
    void setup() {
      Serial.begin(9600);
      while (!Serial) {}  // انتظر حتى يتم فتح منفذ التسلسلي.
      delay(500);         // تتطلب بعض اللوحات تأخيرًا بعد تهيئة منفذ التسلسلي.
      Serial.println("foo");
      Serial.println("bar");
    }
    void loop() {}
    
  5. حدد Tools > Serial Monitor من قوائم Arduino IDE لفتح عرض Serial Monitor، إذا لم يكن مفتوحًا بالفعل.
  6. حدد " 9600 " من قائمة معدل الباود في عرض Serial Monitor.
  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 يلتف بشكل غير صحيح كل سطر من المحتوى المنسوخ من نوع “text/html” في علامات <pre>، فإن عرض كل سطر من المحتوى الملصق ككتلة كود منفصلة بواسطة محرر النصوص المنسقة لـ Discourse هو صحيح ومتوقع.

كما هو الحال مع المشكلة الأخرى التي وصفتها أعلاه، يمكن تجنب التنسيق غير المتوقع عن طريق تشغيل تنسيق كتلة الكود بشكل استباقي قبل لصق المحتوى.

إعجابَين (2)