نظام التركيز

يتتبّع نظام التركيز الموقع الجغرافي للمستخدم (التركيز) في محرّر Blockly. يتم استخدامها من قِبل Blockly والرموز المخصّصة لتحديد المكوّن (الكتلة أو الحقل أو فئة صندوق الأدوات أو غير ذلك) الذي يتم التركيز عليه حاليًا، ولنقل التركيز إلى مكوّن آخر.

من المهم فهم نظام التركيز حتى تتمكّن من ضمان عمل الرمز المخصّص بشكل صحيح معه.

الهندسة المعمارية

يتضمّن نظام التركيز ثلاثة أجزاء:

  • FocusManager هي عنصر فردي ينسّق التركيز على مستوى جميع عناصر Blockly. يتم استخدامها من قِبل Blockly والرموز المخصّصة لمعرفة العنصر الذي يركّز عليه Blockly، بالإضافة إلى نقل تركيز Blockly إلى عنصر آخر. ويستمع أيضًا إلى أحداث التركيز في DOM، ويُزامِن التركيز في Blockly مع التركيز في DOM، ويدير فئات CSS التي تشير إلى المكوّن الذي يتم التركيز عليه.

    يتم استخدام أداة إدارة التركيز بشكل أساسي من خلال Blockly. ويتم استخدامها أحيانًا من خلال الرموز المخصّصة للتفاعل مع نظام التركيز.

  • IFocusableTree هي مساحة مستقلة في محرّر Blockly، مثل مساحة العمل أو صندوق الأدوات. وهي تتألف من عُقد قابلة للتركيز، مثل الحقول والكتل. يمكن أن تحتوي الأشجار أيضًا على أشجار فرعية. على سبيل المثال، مساحة عمل معدِّل على أحد الكتل في مساحة العمل الرئيسية هي شجرة فرعية من مساحة العمل الرئيسية.

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

  • IFocusableNode هو أحد مكوّنات Blockly التي يمكن أن تكون نشطة، مثل كتلة أو حقل أو فئة في صندوق الأدوات. تحتوي العُقد التي يمكن التركيز عليها على عنصر DOM يعرض العقدة ويكون التركيز على DOM عند التركيز على العقدة في Blockly. يُرجى العِلم أنّ الأشجار هي أيضًا عقد يمكن التركيز عليها. على سبيل المثال، يمكنك التركيز على مساحة العمل ككل.

    يتم استدعاء الطرق في IFocusableNode بشكل أساسي من خلال مدير التركيز.

    يُستخدَم IFocusableNode نفسه لتمثيل المكوّن الذي يتم التركيز عليه. على سبيل المثال، عندما يختار مستخدم عنصرًا من قائمة السياق الخاصة بأحد المربّعات، يتم تمرير المربّع إلى دالة رد الاتصال الخاصة بالعنصر كـ IFocusableNode.

    إذا كنت تكتب مكوّنات مخصّصة، قد تحتاج إلى تنفيذ IFocusableNode.

أنواع التركيز

يحدّد نظام التركيز عددًا من أنواع التركيز المختلفة.

التركيز على Blockly والتركيز على DOM

النوعان الرئيسيان للتركيز هما التركيز على Blockly والتركيز على DOM.

  • تحدّد السمة Blockly focus عنصر Blockly الذي يتم التركيز عليه (مثل كتلة أو حقل أو فئة في صندوق الأدوات وما إلى ذلك). وهو ضروري للعمل على مستوى مكونات Blockly. على سبيل المثال، يسمح المكوّن الإضافي للتنقّل باستخدام لوحة المفاتيح للمستخدمين باستخدام مفاتيح الأسهم للانتقال من مكوّن إلى آخر، مثل الانتقال من كتلة إلى حقل. وبالمثل، ينشئ نظام قائمة السياقات قائمة مناسبة للمكوّن الحالي، أي أنّه ينشئ قوائم مختلفة لمساحات العمل والكتل وتعليقات مساحة العمل.

  • تحدّد التركيز على DOM عنصر DOM الذي يتم التركيز عليه. وهي ضرورية للعمل على مستوى عناصر DOM. على سبيل المثال، تعرض برامج قراءة الشاشة معلومات حول العنصر الذي يتم التركيز عليه حاليًا في DOM، وتنتقل علامات التبويب (تغيّر التركيز) من عنصر DOM إلى آخر.

يحافظ مدير التركيز على مزامنة التركيز في Blockly والتركيز في DOM، لذا عندما يكون لدى عقدة (مكوّن Blockly) التركيز في Blockly، يكون لدى عنصر DOM الأساسي التركيز في DOM، والعكس صحيح.

التركيز النشط والتركيز غير النشط

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

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

يستخدم مدير التركيز تمييزات مختلفة (فئات CSS) للعُقد التي يتم التركيز عليها بشكل نشط وغير نشط. تتيح هذه العناصر للمستخدمين معرفة مكانهم والمكان الذي سيعودون إليه.

التركيز المؤقت

هناك نوع آخر من التركيز يُعرف باسم التركيز المؤقت. تطلب إجراءات سير العمل المنفصلة، مثل مربّعات الحوار أو أدوات تعديل الحقول، التركيز المؤقت من مدير التركيز. عندما يمنح مدير التركيز تركيزًا مؤقتًا، يعلّق نظام التركيز. من الناحية العملية، يعني ذلك أنّ مسارات العمل هذه يمكنها رصد أحداث التركيز في نموذج المستند (DOM) واتّخاذ إجراءات بشأنها بدون القلق من أنّ نظام التركيز قد يتّخذ إجراءات بشأنها أيضًا.

عندما يمنح مدير التركيز تركيزًا مؤقتًا، يتم تغيير العقدة التي يتم التركيز عليها بشكل نشط إلى تركيز سلبي. يتم استعادة التركيز النشط عند إرجاع التركيز المؤقت.

أمثلة

توضّح الأمثلة التالية كيفية استخدام Blockly لنظام التركيز. ويجب أن تساعدك هذه المستندات في فهم كيفية توافق الرمز البرمجي مع نظام التركيز وكيفية استخدام الرمز البرمجي لنظام التركيز.

نقل التركيز باستخدام لوحة المفاتيح

لنفترض أنّ هناك مربّعًا يحتوي على حقلَين ويتم التركيز عليه في Blockly، كما هو موضّح من خلال التمييز (فئة CSS) على عنصر DOM الخاص بالمربّع. لنفترض الآن أنّ المستخدم يضغط على سهم الاتجاه الأيسر:

  1. إضافة التنقّل باستخدام لوحة المفاتيح:
    • تتلقّى حدث ضغط على مفتاح.
    • يطلب من نظام التنقّل (وهو جزء من Blockly الأساسي) نقل التركيز إلى المكوّن "التالي".
  2. نظام التنقّل:
    • يطلب من مدير التركيز معرفة المكوّن الذي يركّز عليه Blockly. يعرض مدير التركيز الكتلة كـ IFocusableNode.
    • تحدّد هذه السمة أنّ IFocusableNode هي BlockSvg، وتطّلع على قواعدها الخاصة بالتنقّل بين الحقول، والتي تنص على أنّه يجب نقل تركيز Blockly من الحقل ككل إلى الحقل الأول فيه.
    • يطلب من مدير التركيز نقل تركيز Blockly إلى الحقل الأول.
  3. مدير التركيز:
    • تعدّل حالتها لضبط تركيز Blockly على الحقل الأول.
    • يضبط التركيز على عنصر DOM الخاص بالحقل.
    • تنقل هذه السمة فئة التمييز من عنصر الكتلة إلى عنصر الحقل.

نقل التركيز باستخدام الماوس

لنفترض الآن أنّ المستخدم ينقر على الحقل الثاني في الكتلة. مدير التركيز:

  1. يتلقّى حدث focusout DOM على عنصر DOM الخاص بالحقل الأول وحدث focusin على عنصر DOM الخاص بالحقل الثاني.
  2. تحدّد هذه السمة أنّ عنصر DOM الذي تم التركيز عليه يتوافق مع الحقل الثاني.
  3. تعدّل حالتها لضبط تركيز Blockly على الحقل الثاني. (لا يحتاج مدير التركيز إلى ضبط تركيز DOM لأنّ المتصفّح قد فعل ذلك من قبل).
  4. ينقل هذا الإجراء فئة التمييز من عنصر الحقل الأول إلى عنصر الحقل الثاني.

أمثلة أخرى

في ما يلي بعض الأمثلة الأخرى:

  • عندما يسحب المستخدم أحد المربّعات من صندوق الأدوات إلى مساحة العمل، ينشئ معالج حدث الماوس مربّعًا جديدًا ويطلب من مدير التركيز ضبط تركيز Blockly على هذا المربّع.

  • عند حذف أحد الحظر، تستدعي طريقة dispose مدير التركيز لنقل التركيز إلى العنصر الرئيسي للحظر.

  • تستخدِم اختصارات لوحة المفاتيح الرمز IFocusableNode لتحديد عنصر Blockly الذي ينطبق عليه الاختصار.

  • تستخدم قوائم السياق IFocusableNode لتحديد مكوّن Blockly الذي تم استدعاء القائمة عليه.

عمليات التخصيص ونظام التركيز

عند تخصيص Blockly، عليك التأكّد من أنّ الرمز البرمجي يعمل بشكل صحيح مع نظام التركيز. يمكنك أيضًا استخدام نظام التركيز لتحديد وضبط العقدة التي يتم التركيز عليها حاليًا.

الكتل المخصّصة ومحتوى صندوق الأدوات

الطريقة الأكثر شيوعًا لتخصيص Blockly هي تحديد مربّعات مخصّصة وتخصيص محتوى صندوق الأدوات. ولا يؤثر أي من هذين الإجراءين في نظام التركيز.

الصفوف المخصّصة

قد تحتاج الفئات المخصّصة إلى تنفيذ إحدى واجهتَي التركيز أو كلتيهما (IFocusableTree وIFocusableNode)، ولكن ليس من الواضح دائمًا متى يكون ذلك ضروريًا.

من الواضح أنّ بعض الفئات تحتاج إلى تنفيذ واجهات التركيز. ومن بينها:

  • فئة تنفّذ مجموعة أدوات مخصّصة يجب أن تنفّذ هذه الفئة IFocusableTree وIFocusableNode.

  • الفئات التي تنشئ مكونًا مرئيًا (مثل حقل أو رمز) يمكن للمستخدمين الانتقال إليه. يجب أن تنفّذ هذه الفئات IFocusableNode.

يجب أن تنفّذ بعض الفئات IFocusableNode حتى إذا لم تنشئ عنصرًا مرئيًا أو أنشأت عنصرًا مرئيًا لا يمكن للمستخدمين الانتقال إليه. ومن بينها:

  • الفئات التي تنفّذ واجهة توسّع IFocusableNode

    على سبيل المثال، يعرض رمز النقل في إضافة التنقّل باستخدام لوحة المفاتيح سهمًا رباعي الاتجاه يشير إلى أنّه يمكن نقل الكتلة باستخدام مفاتيح الأسهم. لا يظهر الرمز نفسه (السهم الرباعي الاتجاه عبارة عن فقاعة) ولا يمكن للمستخدمين الانتقال إليه. ومع ذلك، يجب أن يتضمّن الرمز IFocusableNode لأنّ الرموز تتضمّن IIcon وIIcon يمتد إلى IFocusableNode.

  • الفئات المستخدَمة في واجهة برمجة تطبيقات تتطلّب IFocusableNode

    على سبيل المثال، تنشئ الفئة FlyoutSeparator فجوة بين عنصرين في قائمة منبثقة. ولا ينشئ أي عناصر DOM، لذا ليس لديه مكوّن مرئي ولا يمكن للمستخدمين الانتقال إليه. ومع ذلك، يجب أن تنفّذ IFocusableNode لأنّها مخزّنة في FlyoutItem ويتطلّب منشئ FlyoutItem توفّر IFocusableNode.

  • الفئات التي توسّع فئة تنفّذ IFocusableNode

    على سبيل المثال، ToolboxSeparator يمتد إلى ToolboxItem، الذي ينفّذ IFocusableNode. على الرغم من أنّ فواصل شريط الأدوات تتضمّن عنصرًا مرئيًا، لا يمكن للمستخدمين الانتقال إليها لأنّه لا يمكن التفاعل معها ولا تتضمّن أي محتوى مفيد.

تنشئ الفئات الأخرى مكونات مرئية يمكن للمستخدم الانتقال إليها، ولكنها لا تحتاج إلى تنفيذ IFocusableNode. ومن بينها:

  • الفئات التي تنشئ مكونًا مرئيًا يدير التركيز الخاص به، مثل محرّر الحقول أو مربّع الحوار (يُرجى العِلم أنّ هذه الفئات تحتاج إلى الحصول على التركيز المؤقت عند بدء تشغيلها وإعادته عند انتهاء تشغيلها. سيتم التعامل مع ذلك تلقائيًا عند استخدام WidgetDiv أو DropDownDiv).

أخيرًا، لا تتفاعل بعض الفئات مع نظام التركيز ولا تحتاج إلى تنفيذ IFocusableTree أو IFocusableNode. ومن بينها:

  • الفئات التي تنشئ مكونًا مرئيًا لا يمكن للمستخدمين الانتقال إليه أو التفاعل معه ولا يحتوي على أي معلومات قد يستخدمها قارئ الشاشة على سبيل المثال، خلفية مزخرفة في لعبة.

  • فئات غير مرتبطة بنظام التركيز، مثل الفئات التي تنفّذ IMetricsManager أو IVariableMap

إذا لم تكن متأكدًا مما إذا كان صفك سيتفاعل مع نظام التركيز، اختبِره باستخدام المكوّن الإضافي للتنقّل باستخدام لوحة المفاتيح. إذا لم ينجح ذلك، قد تحتاج إلى تنفيذ IFocusableTree أو IFocusableNode. إذا نجح ذلك ولكنك ما زلت غير متأكّد، اقرأ الرمز الذي يستخدم صفك لمعرفة ما إذا كانت أي من الواجهتين مطلوبة أو إذا كانت هناك أي تفاعلات أخرى.

تنفيذ واجهات التركيز

إنّ أسهل طريقة لتنفيذ IFocusableTree أو IFocusableNodeهي توسيع فئة تنفّذ هاتين الواجهتين. على سبيل المثال، إذا كنت تنشئ مجموعة أدوات مخصّصة، يمكنك توسيع Toolbox، التي تنفّذ IFocusableTree وIFocusableNode. إذا كنت بصدد إنشاء حقل مخصّص، عليك توسيع Field، الذي ينفّذ IFocusableNode. تأكَّد من أنّ الرمز البرمجي لا يتعارض مع رمز واجهة التركيز في الفئة الأساسية.

إذا كنت بصدد توسيع فئة تنفّذ واجهة تركيز، لن تحتاج عادةً إلى إلغاء أي طرق. الاستثناء الأكثر شيوعًا هو IFocusableNode.canBeFocused، والذي عليك إلغاؤه إذا كنت لا تريد أن ينتقل المستخدمون إلى المكوّن.

من غير الشائع الحاجة إلى إلغاء طرق معاودة الاتصال الخاصة بالتركيز (onTreeFocus وonTreeBlur في IFocusableTree وonNodeFocus وonNodeBlur في IFocusableNode)، ولكن يجب الانتباه إلى أنّ محاولة تغيير التركيز (استدعاء FocusManager.focusNode أو FocusManager.focusTree) من خلال هذه الطرق تؤدي إلى حدوث استثناء.

إذا كتبت مكوّنًا مخصّصًا من البداية، عليك تنفيذ واجهات التركيز بنفسك. لمزيد من المعلومات، يُرجى الاطّلاع على المستندات المرجعية الخاصة بـ IFocusableTree وIFocusableNode.

بعد تنفيذ الفئة، اختبِرها باستخدام المكوّن الإضافي "التنقّل باستخدام لوحة المفاتيح" للتأكّد من إمكانية (أو عدم إمكانية) الانتقال إلى المكوّن.

استخدام "أداة إدارة التركيز"

تستخدِم بعض الفئات المخصّصة أداة إدارة التركيز. تتضمّن الأسباب الأكثر شيوعًا لذلك الحصول على العقدة التي يتم التركيز عليها حاليًا والتركيز على عقدة مختلفة. للحصول على أداة إدارة التركيز، اتّصِل بالرقم Blockly.getFocusManager:

const focusManager = Blockly.getFocusManager();

للحصول على العقدة التي يتم التركيز عليها حاليًا، استخدِم الرمز getFocusedNode:

const focusedNode = focusManager.getFocusedNode();
// Do something with the focused node.

لنقل التركيز إلى عقدة مختلفة، استخدِم focusNode:

// Move focus to a different block.
focusManager.focusNode(myOtherBlock);

لنقل التركيز إلى شجرة، استخدِم الأمر focusTree. يؤدي ذلك أيضًا إلى ضبط تركيز العقدة على عقدة الجذر في الشجرة.

// Move focus to the main workspace.
focusManager.focusTree(myMainWorkspace);

والسبب الشائع الآخر لاستخدام أداة إدارة التركيز هو الحصول على التركيز المؤقت وإعادته. تعرض الدالة takeEphemeralFocus دالة lambda يجب استدعاؤها لعرض التركيز المؤقت.

const returnEphemeralFocus = focusManager.takeEphemeralFocus();
// Do something.
returnEphemeralFocus();

إذا كنت تستخدم WidgetDiv أو DropDownDiv، ستتولّى هذه الخدمات إدارة التركيز المؤقت نيابةً عنك.

علامات الجدولة

يضبط نظام التركيز موضع توقّف علامة التبويب (tabindex من 0) على العنصر الجذر لجميع الأشجار (مساحة العمل الرئيسية، وصندوق الأدوات، ومساحات العمل المنبثقة). يتيح ذلك للمستخدمين استخدام مفتاح التبويب للتنقّل بين المناطق الرئيسية في محرّر Blockly، ثم استخدام مفاتيح الأسهم للتنقّل داخل تلك المناطق (باستخدام مكوّن التنقّل باستخدام لوحة المفاتيح الإضافي). لا تغيّر مواضع التوقف هذه لأنّ ذلك سيتعارض مع قدرة مدير التركيز على إدارتها.

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

من الآمن ضبط مواضع التوقف في علامات التبويب على العناصر في تطبيقك التي تقع خارج محرِّر Blockly. عندما ينتقل المستخدم من المحرّر إلى أحد هذه العناصر باستخدام مفتاح Tab، يغيّر مدير التركيز تركيز Blockly من نشط إلى غير نشط. لتحسين إمكانية الوصول، عليك ضبط السمة tabindex على 0 أو -1، كما هو مقترح في التحذير الوارد في وصف السمة tabindex على شبكة مطوّري Mozilla.

التركيز على DOM

لأسباب تتعلق بإمكانية الوصول، يجب أن تتجنّب التطبيقات استدعاء طريقة focus على عناصر DOM. ويؤدي ذلك إلى إرباك مستخدمي برامج قراءة الشاشة لأنّه يتم نقلهم فجأة إلى مكان غير معروف في التطبيق.

تتمثل إحدى المشاكل الإضافية في أنّ أداة إدارة التركيز تتفاعل مع أحداث التركيز من خلال ضبط التركيز على أقرب عنصر أصل أو العنصر نفسه الذي تم التركيز عليه، على أن يكون هذا العنصر قابلاً للتركيز. قد يختلف هذا عن العنصر الذي تم استدعاء focus عليه. (إذا لم يكن هناك عنصر رئيسي أو عنصر ذاتي قابل للتركيز، مثلما يحدث عند استدعاء focus على عنصر خارج محرِّر Blockly، يغيّر مدير التركيز العقدة النشطة التي تم التركيز عليها إلى تركيز سلبي.)

العناصر القابلة للتحديد موضعها

العناصر القابلة للتحديد هي مكوّنات يتم وضعها فوق مساحة العمل وتنفّذ IPositionable. وتشمل الأمثلة سلة المهملات وحقيبة الظهر في مكوّن حقيبة الظهر الإضافي. لم يتم دمج العناصر القابلة للتحديد في نظام التركيز بعد.