ينشئ هذا الدليل أبسط نموذج أولي مفيد وفق Manifest V3 في Chrome: حقل نص خاص يظهر في صفحات دبابيس Pinterest، ويستخدم معرّف الدبوس الرقمي مفتاحًا، ويحفظ البيانات في chrome.storage.local. صُمم هذا المثال عمدًا كنموذج أولي، لا كنسخة جاهزة للإنتاج من ميزة ملاحظات Pinterest السابقة.
قد تتغير شجرة DOM في Pinterest من دون إشعار. اعزل محددات العناصر، ولا تحاكِ الهوية التجارية المحمية لـPinterest، واختبر الإضافة في جميع أنواع الصفحات والإصدارات المحلية التي تقول إنك تدعمها.
1. أنشئ إضافة Manifest V3
أنشئ مجلدًا يحتوي على manifest.json و content.js. ويُعد مرجع ملف البيان في Chrome المصدر المعتمد لمعرفة المفاتيح المتاحة.
{ "manifest_version": 3, "name": "Pin Context Prototype", "version": "0.1.0", "description": "Save a private local note for a Pinterest Pin.", "permissions": ["storage"], "content_scripts": [{ "matches": ["https://*.pinterest.com/*"], "js": ["content.js"], "run_at": "document_idle" }] }
نطاق المطابقة واسع لأن Pinterest يستخدم التنقل من جهة العميل. إذا كانت ميزتك تعمل في مسارات أقل أو في نطاقات دول محددة، فضيّق نطاق المطابقة ووثّقه.
2. استخرج مفتاحًا ثابتًا من عنوان URL للدبوس
لا تستخدم موضع البطاقة أو عنوانها الظاهر مفتاحًا للملاحظة. استخرج المعرّف الرقمي من مسار قياسي على النمط /pin/…/ وأعِد القيمة null في كل الحالات الأخرى.
function getPinId(url = location.href) { try { const { pathname } = new URL(url); const match = pathname.match(/\/pin\/(\d+)\/?/); return match ? match[1] : null; } catch { return null; } }
اختبر عناوين صفحات التفاصيل الصحيحة، ومعلمات الاستعلام، والصفحات التي لا تعرض دبوسًا، والعناوين غير الصالحة، وأنماط اللغات التي تدّعي دعمها. لا تربط ملاحظة بصمت عندما لا تكون واثقًا من المعرّف.
3. خزّن سجلًا ذا إصدار محدد
اجعل مخطط البيانات صريحًا حتى تتمكن من ترحيله مستقبلًا:
async function readNote(pinId) { const key = 'pin-note:' + pinId; const result = await chrome.storage.local.get(key); return result[key] ?? { version: 1, pinId, text: '', updatedAt: null }; } async function writeNote(pinId, text) { const key = 'pin-note:' + pinId; const record = { version: 1, pinId, text, updatedAt: new Date().toISOString() }; await chrome.storage.local.set({ [key]: record }); return record; }
توضح وثائق Chrome أن الحد الافتراضي لمساحة storage.localهو 10 ميغابايت، مع إذن مستقل باسم unlimitedStorage لزيادة السعة. وتوضح الوثائق أيضًا أن بيانات التخزين المحلي للإضافة تُحذف عند إزالة الإضافة. اقرأ الوثائق الحالية لواجهة Storage API وصمّم آلية التصدير قبل أن تطلب من المستخدمين حفظ بيانات مهمة.
4. أضف محررًا معزولًا يراعي إتاحة الوصول
تقلل تقنية Shadow DOM تعارضات التنسيق غير المقصودة. يضيف المثال العنصر إلى جسم الصفحة، فلا يعتمد على اسم فئة في Pinterest قد يتغير بسهولة:
async function mountEditor(pinId) { if (document.querySelector('[data-pin-context-root]')) return; const host = document.createElement('aside'); host.dataset.pinContextRoot = ''; host.setAttribute('aria-label', 'Private Pin note'); document.body.append(host); const root = host.attachShadow({ mode: 'open' }); const label = document.createElement('label'); label.textContent = 'Private note'; const editor = document.createElement('textarea'); editor.id = 'pin-note-editor'; label.htmlFor = editor.id; editor.setAttribute('aria-label', 'Private note for this Pin'); const status = document.createElement('span'); status.setAttribute('role', 'status'); const saved = await readNote(pinId); editor.value = saved.text; root.append(label, editor, status); bindAutosave(editor, status, pinId); }
أنشئ نصوص الواجهة باستخدام textContent، لا باستخدام قيمة غير موثوقة في innerHTML. وأضف نمطًا واضحًا لحالة التركيز، وتباينًا كافيًا، وتسمية فعلية للحقل، وإمكان استخدام لوحة المفاتيح، ورسالة حالة لا تنقل بؤرة الإدخال.
5. احفظ من دون الكتابة إلى التخزين مع كل ضغطة مفتاح
function bindAutosave(editor, status, pinId) { let saveTimer; editor.addEventListener('input', () => { status.textContent = 'Unsaved'; clearTimeout(saveTimer); saveTimer = setTimeout(async () => { try { await writeNote(pinId, editor.value); status.textContent = 'Saved locally'; } catch (error) { console.error('Pin note save failed', error); status.textContent = 'Could not save'; } }, 400); }); }
في نسخة الإنتاج، احفظ أيضًا أي إدخال معلّق عند الانتقال إلى صفحة أخرى، وامنع تبويبين من الكتابة فوق تعديلات بعضهما، وحدد حجمًا أقصى للملاحظة، واعرض أخطاء تجاوز السعة للمستخدم.
6. تعامل مع تنقل Pinterest من جهة العميل
لن يكتشف معالج يعمل مرة واحدة عند تحميل الصفحة الانتقال بين الخلاصة وصفحة التفاصيل. استخدم دالة تسوية تعطي النتيجة نفسها عند تكرارها، وراقب التغييرات من دون إعادة تركيب الواجهة بعد كل تعديل في DOM:
let scheduled = false; async function reconcile() { scheduled = false; const pinId = getPinId(); const existing = document.querySelector('[data-pin-context-root]'); if (!pinId) { existing?.remove(); return; } if (existing?.dataset.pinId === pinId) return; existing?.remove(); await mountEditor(pinId); const mounted = document.querySelector('[data-pin-context-root]'); if (mounted) mounted.dataset.pinId = pinId; } new MutationObserver(() => { if (scheduled) return; scheduled = true; requestAnimationFrame(reconcile); }).observe(document.documentElement, { childList: true, subtree: true }); reconcile();
ينبغي لنسخة الإنتاج أيضًا مراقبة حالة التنقل مباشرةً متى أمكن، وفصل المراقبين الذين لم تعد تحتاج إليهم. قِس أداء الشفرة في الخلاصات الطويلة؛ فالخاصية الصحيحة وظيفيًا تظل سيئة إذا أبطأت الصفحة.
7. التزم بقيود الأمان في Manifest V3
يحظر Manifest V3 تشغيل شيفرة تنفيذية مستضافة عن بُعد. ضمّن شيفرة JavaScript التنفيذية داخل حزمة الإضافة، واحتفظ بسياسة أمان المحتوى الافتراضية ما لم يكن لديك سبب موثق لتغييرها، وتجنب تنفيذ الشيفرة ديناميكيًا، ولا تطلب إلا الأذونات التي تحتاج إليها الميزة. يشرح دليل Chrome إلى Manifest V3 نموذج المنصة.
8. أضف ما يحتاج إليه المنتج الحقيقي
- تصدير JSON واستيراده، مع التحقق من المخطط ومعالجة التعارضات؛
- تصدير مقروء مباشرةً لأغراض الاستعادة؛
- البحث والوسوم الاختيارية؛
- عرض استخدام مساحة التخزين وحدودها؛
- حذف ملاحظة منفردة أو جميع البيانات؛
- سياسة خصوصية تطابق السلوك الذي يمكن التحقق منه؛
- اختبارات ترحيل بين إصدارات مخطط البيانات؛
- تحذيرات واضحة بشأن إزالة الإضافة وعدم وجود مزامنة؛
- بيانات قياس للأخطاء لا تجمع إلا الحد الأدنى الضروري مع إفصاح واضح.
9. اختبر حالات الفشل
- حمّل الإضافة غير المضغوطة من
chrome://extensions. - افتح خلاصة ولوحة وصفحة تفاصيل دبوس ومسارًا لا يعرض دبوسًا.
- انتقل بين دبوسين من دون إعادة تحميل الصفحة، وتأكد من بقاء ملاحظة كل دبوس معزولة.
- افتح الدبوس نفسه في تبويبين واختبر طريقة التعامل مع التعارض.
- عطّل التخزين أو حاكِ تجاوز سعته، وتأكد من ظهور التحذير.
- صدّر البيانات، واحذف سجلًا تجريبيًا، ثم استعده.
- اختبر التنقل بلوحة المفاتيح، والتكبير، وتسميات قارئ الشاشة، وظهور الواجهة على الصفحات الداكنة والفاتحة.
الخلاصة الهندسية
حقل النص هو الجزء السهل. أما إضافة Pinterest الجديرة بالثقة فتعتمد على معرّف ثابت، وإدارة متينة لدورة الحياة، وواجهة تراعي إتاحة الوصول، وأذونات محدودة، وتخزين موثق، وطريقة مجرّبة لاستخراج البيانات واستعادتها. ابنِ هذه الأسس قبل توسيع قائمة الميزات.
واصل تحسين طريقة تنظيمك في Pinterest
انتقل إلى الدليل الذي يناسب خطوتك التالية:
جرّب إضافة Notestopin لمتصفح Chrome
أضف ملاحظات خاصة ووسومًا إلى أي دبوس، ثم اعثر بسهولة على كل ما حفظته.
إضافة إلى Chrome