إضافات Chrome: توسيع واجهة برمجة التطبيقات لإتاحة التنقل الفوري

ديف تابوسكا
"ديف تابوسكا"

النصّ المختصر (TL;DR): تم تحديث واجهة برمجة التطبيقات Accessibility API لإتاحة إمكانية التخزين المؤقت باستخدام ميزة "التخزين المؤقت للصفحات" وعمليات الانتقال المُسبقة التحميل. يُرجى الاطّلاع على التفاصيل أدناه.

يعمل Chrome جاهدين على تسريع عملية التنقل. تعمل تقنيات التنقّل الفوري مثل التخزين المؤقت للصفحات (التي يتم شحنها على الكمبيوتر المكتبي في Chrome 96) وقواعد التوقُّع (التي تم شحنها في Chrome 103) على تحسين تجربة الرجوع والمستقبل. في هذه المشاركة، سنستكشف التحديثات التي أجريناها على واجهات برمجة التطبيقات لإضافات المتصفح لتلائم عمليات سير العمل الجديدة هذه.

فهم أنواع الصفحات

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

إزالة الصفحة النشطة
إخلاء الصفحة النشطة:

من خلال ميزة "التخزين المؤقت للصفحات" وميزة "العرض المُسبَق"، لم يعُد هناك علاقة فردية بين علامات التبويب والصفحات. الآن، تخزن كل علامة تبويب بالفعل عدة صفحات وصفحات تنتقل بين الحالات بدلاً من تدميرها وإعادة بنائها.

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

أنواع الصفحات
أنواع الصفحات

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

ما التغييرات التي طرأت على مطوّري الإضافات؟

معرِّف الإطار == 0

في Chromium، نشير إلى الجزء العلوي/الإطار الرئيسي بوصفه الإطار الخارجي.

قد يواجه مؤلفو الإضافات الذين يفترضون frameId للإطار الخارجي 0 (من أفضل الممارسات السابقة) مشاكل. ونظرًا لأن علامة التبويب يمكن أن تحتوي الآن على إطارات خارجية متعددة (صفحات معروضة مسبقًا ومخزّنة مؤقتًا)، فإن الافتراض بأن هناك إطارًا خارجيًا واحدًا غير صحيح لعلامة التبويب. ستظلّ السمة frameId == 0 تمثّل الإطار الخارجي للصفحة النشطة، ولكن ستكون الإطارات الخارجية للصفحات الأخرى في علامة التبويب نفسها قيمة غير صفرية. تمت إضافة حقل frameType جديد لإصلاح هذه المشكلة. راجِع قسم "كيف يمكنني تحديد ما إذا كان الإطار هو الإطار الخارجي؟" في هذه المشاركة.

دورة حياة الإطارات مقابل المستندات

مفهوم آخر يمثل مشكلة في الإضافات هو دورة حياة الإطار. يستضيف الإطار مستندًا (مرتبطًا بعنوان URL مخصص). يمكن أن يتغير المستند (على سبيل المثال من خلال التنقل) ولكن لن يحدث ذلك مع frameId، وبالتالي من الصعب ربط ما حدث في مستند معين بـ frameId فقط. نحن بصدد تقديم مفهوم documentId، وهو معرِّف فريد لكل مستند. إذا تم التنقل في إطار وفتح مستندًا جديدًا، فإن المعرّف سيتغير. يُعد هذا الحقل مفيدًا لتحديد الحالات التي تغيّر فيها الصفحات حالة دورة حياتها (بين العرض المسبق/النشط/التخزين المؤقت) لأنها تظل كما هي.

أحداث التنقّل على الويب

يمكن تنشيط الأحداث في مساحة الاسم chrome.webNavigation عدة مرات على الصفحة نفسها استنادًا إلى دورة الحياة. اطّلِع على القسمَين "كيف أعرف دورة حياة الصفحة؟" و"كيف يمكنني تحديد وقت انتقال الصفحة؟".

كيف يمكنني معرفة دورة حياة الصفحة؟

تمت إضافة النوع DocumentLifecycle إلى عدد من واجهات برمجة التطبيقات للإضافات حيث كان frameId متاحًا في السابق. إذا كان النوع DocumentLifecycle متوفّرًا في حدث معيّن (مثل onCommitted)، تكون قيمته هي الحالة التي تم إنشاء الحدث فيها. يمكنك دائمًا طلب البحث عن المعلومات من خلال طريقتَي WebNavigation getFrame() وgetAllFrames()، ولكن يُفضَّل دائمًا استخدام القيمة من الحدث. إذا استخدمت أيًّا من الطريقتين، تذكَّر أنّ حالة الإطار قد تتغيّر بين وقت إنشاء الحدث ووقت حلّ الوعود باستخدام كلتا الطريقتين.

يحتوي DocumentLifecycle على القيم التالية:

  • "prerender" : لا يتم عرضه للمستخدم حاليًا ولكنه يستعد للعرض للمستخدم.
  • "active": يتم عرضه للمستخدم حاليًا.
  • "cached": يتم التخزين في ذاكرة التخزين المؤقت باستخدام ميزة "التخزين المؤقت للصفحات".
  • "pending_deletion": يتم إتلاف المستند.

كيف يمكنني تحديد ما إذا كان الإطار هو الإطار الخارجي؟

في السابق، كانت الإضافات تتحقّق مما إذا كان frameId == 0 سيحدّد ما إذا كان الحدث الذي يقع في الإطار الخارجي أم لا. نظرًا لوجود صفحات متعددة في علامة التبويب، أصبح لدينا الآن إطارات خارجية متعددة، لذا يشكّل تعريف frameId مشكلة. ولن تتلقى مطلقًا أي أحداث تتعلق بالإطار الذي تم تخزينه مؤقتًا باستخدام ميزة "التخزين المؤقت للصفحات". ومع ذلك، بالنسبة إلى الإطارات المعروضة مُسبقًا، ستكون قيمة frameId غير صفرية للإطار الخارجي. لذا، فإن استخدام frameId == 0 كإشارة لتحديد ما إذا كان الإطار الخارجي غير صحيح.

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

  • "outermost_frame": يُشار إليه عادةً على أنه الإطار العلوي. لاحظ أن هناك مضاعفات منها. على سبيل المثال، إذا كانت لديك صفحات معروضة مسبقًا ومخزّنة مؤقتًا، فيحتوي كل منها على إطار خارجي يمكن تسمية إطاره العلوي.
  • "fenced_frame": محجوزة للاستخدام المستقبلي.
  • "sub_frame": عادةً ما يكون إطار iframe.

يمكننا الدمج بين DocumentLifecycle وFrameType وتحديد ما إذا كان الإطار هو الإطار الخارجي النشط. مثلاً: js tab.documentLifecycle == “active” && frameType == “outermost_frame”

كيف يمكنني حلّ مشاكل وقت استخدام الإطارات؟

كما ذكرنا أعلاه، يستضيف الإطار مستندًا وقد ينتقل الإطار إلى مستند جديد، ولكن لن تتغير frameId. ويحدث ذلك مشاكل عند تلقّي حدث باستخدام frameId فقط. إذا بحثت عن عنوان URL للإطار، قد يكون مختلفًا عن وقت وقوع الحدث، ويُعرف ذلك باسم "مشكلة وقت الاستخدام".

لمعالجة هذا الأمر، طرحنا documentIdparentDocumentId). تجعل طريقة webNavigation.getFrame() الآن frameId اختيارية في حال توفير documentId. سيتغير documentId عندما يتم التنقل في إطار.

كيف يمكنني تحديد وقت انتقال الصفحة؟

هناك إشارات واضحة لتحديد وقت انتقال الصفحة بين الحالات.

لنلقِ نظرة على حدثَي WebNavigation.

للانتقال لأول مرة في أي صفحة، سترى أربعة أحداث بالترتيب المدرَج أدناه. يُرجى العِلم أنّ هذه الأحداث الأربعة يمكن أن تقع عندما تكون حالة DocumentLifecycle إما "prerender" أو "active".

onBeforeNavigate
onCommitted
onDOMContentLoaded
onCompleted

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

يتغير معرِّف المستند عندما تصبح الصفحة المعروضة مُسبقًا هي الصفحة النشطة.
تتغيّر documentId عندما تصبح الصفحة المعروضة مُسبقًا هي الصفحة النشطة.

عندما يتم نقل صفحة من ذاكرة التخزين المؤقت باستخدام ميزة "التخزين المؤقت للصفحات" أو من خلال عرضها مسبقًا إلى الحالة النشطة، ستظهر ثلاثة أحداث أخرى (ولكن ستكون حالة DocumentLifecyle هي "active").

onBeforeNavigate
onCommitted
onCompleted

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

إذا كانت لديك أي تعليقات أو أسئلة، يُرجى عدم التردد في طرحها على مجموعة chromium-extensions.