هشام رزق الله

الأعضاء
  • المساهمات

    1,443
  • تاريخ الانضمام

  • تاريخ آخر زيارة

  • Days Won

    31

السُّمعة بالموقع

186 Excellent

8 متابعين

  1. إذا لم تسمع بعد عن WebAssembly، فستسمع عنه قريبًا على رغم من وجوده في كل مكان، فهو مدعوم من أغلب المتصفحات (وسيدعم الخادم قريبًا) وهو سريع ويُستخدم في الألعاب، وهو معيار مفتوح من اتحاد شبكة الويب العالميّة (W3C)، والتي هي المنظمة الدولية للمعايير الرئيسيّة لشبكة الإنترنت. ستندهش على الأغلب من ذلك، وسترغب في تعلم البرمجة به، لكن هذا ليس صحيح تمامًا، فأنت لا تكتب شيفرات باستخدام WebAssembly، لنأخذ بعض الوقت ونتعلم حول هذه التكنولوجيات التي تختصر في العادة إلى "Wasm". من أين أتت؟ إذا عدنا لعشرة سنوات إلى الوراء، سنجد أن جافاسكربت لم يكن سريعًا كفاية للكثير من الأشياء، فلغة الجافاسكربت كانت بلا شك ناجحة ومناسبة، فهي تعمل على أي متصفّح وتضيف للصفحات الحيويّة التي نعتبرها أمرًا عاديًا الآن، لكنه كان لغة عاليّة المستوى وهي غير مصمّمة للعمل على أعمال تستهلك الكثير من الحسابات. ومع ذلك، على الرغم من أن المهندسين المسؤولين عن متصفحات الويب الشهيرة كانوا متفقين بشكل عام على مشكلة الأداء، فلم يتفقوا حول حل لها. فلقد ظهر معسكران، بدأت جوجل مشروع عميل Native وبعد ذلك نسخة محمولة منه للتركيز على السماح للألعاب وبقيّة البرامج المكتوبة بلغة C و ‎C++‎ للعمل في مكان آمن في كروم Chrome. وفي نفس الوقت، حصلت Mozilla على دعم Microsoft لـ asm.js، وهو أسلوب لتحديث المتصفح للعمل على مجموعة فرعية من تعليمات جافا سكربت منخفضة المستوى بسرعة كبيرة (ظهر مشروع آخر مكّن من تحويل شيفرات C و C++‎ إلى هذه التعليمات). لم يحصل أي معسكر على تبني واسع، لذلك اتفقوا جميعًا على التعاون في 2015 حول معيار جديد يدعى WebAssembly مبني على نهج بسيط مأخوذ من asm.js، وكما كتب Stephen Shankland في CNET: أعلنت موزيلا في 2017 عن منتج الحد الأدنى (Minimum viable product) للتجربة، وجميع المتصفحات تبنته في نهاية ذلك العام، وفي ديسمبر 2019، أطلقت مجموعة عمل WebAssembly مواصفات WebAssembly الثلاثة كتوصيات W3C. يعرّف WebAssembly صيغة شيفرة بصيغة ثنائية (binary code) محمولة للبرامج التنفيذيّة، و مقابلها بلغة التجميع، وواجهات لتسهيل التفاعل بين هذه البرامج والبيئة المستضيفة. تعمل شيفرة البرمجية لـ WebAssembly في آلات افتراضية ذات مستوى منخفض الذي يحاكي وظائف العديد من المعالجات الدقيقة التي يمكن تشغيلها عن طريق ترجمة فوريّة - Just-In-Time‏ (JIT) - أو تفسير - interpretation -، يمكن لمحرّك WebAssembly العمل بنفس السرعة تقريبًا للترجمة في منصة Native. لماذا الاهتمام الآن؟ يأتي بعض من الإهتمام الأخير بـ WebAssembly من الرغبة في تشغيل شيفرات تستهلك الكثير من الحسابات في المتصفحات، فمستخدمي الحاسوب المحمول على وجه الخصوص، يقضون أغلب أوقاتهم في المتصفح (أو في حالة Chromebooks، كامل وقتهم)، لذلك خلق هذا الاتجاه إلحاحا حول إزالة الحواجز التي تحول دون تشغيل مجموعة كبيرة من التطبيقات في المتصفح، وواحدة من هذه الحواجز هي الأداء، والتي صمم WebAssembly في الأصل لمعالجتها. ومع ذلك، فإن WebAssembly ليس للمتصفحات فقط، ففي عام 2019، أعلنت موزيلا عن مشروع يدعى WASI اختصارًا للعبارة WebAssembly System Interface أي واجهة نظام WebAssembly لوضع معيار لكيفية تعامل شيفرة WebAssembly مع نظام التشغيل خارج سياق المتصفح، وبالجمع ما بين دعم المتصفح لـ WebAssembly و WASI ستتمكن من تشغيل ملفات الثنائيّة المترجمة في داخل وخارج المتصفحات، عن طريق مختلف الأجهزة وأنظمة التشغيل، بسرعة الآلة (Native) تقريبًا. بسبب أعباء WebAssembly المنخفضة سيكون من العملي استخدامه خارج المتصفحات، لكن هنالك العديد من الطرق الأخرى التي يمكننا من خلالها تشغيل تطبيقات بنفس الكفائة، فلماذا نستخدم WebAssembly تحديدًا؟ أهم سبب لهذا هو المحمولية، فاللغات المترجمة المستخدمة اليوم مثل C++‎ و Rust هي الأكثر ارتباطًا بـ WebAssembly اليوم. ومع ذلك، العديد من اللغات الأخرى تترجم إلى أو تملك آلاتها الافتراضيّة في WebAssembly، وعلاوة على ذلك، على الرغم من افتراض WebAssembly لبعض الشروط المسبقة لبيئات التنفيذ، فإنه مصمم للعمل بكفاءة على مجموعة واسعة من أنظمة التشغيل والبنيات، لذلك يمكن كتابة شيفرة WebAssembly باستخدام مجموعة واسعة من اللغات على نطاق واسع من أنظمة التشغيل وأنواع المعالجات. تنبع ميّزة WebAssembly أخرى، من حقيقة أن الشيفرة البرمجية تعمل في آلة افتراضيّة، ونتيجة لذلك، كل وحدة WebAssembly تنفذ في بيئة منعزلة عن وقت تنفيذ المضيف باستخدام تقنية عزل الخطأ (fault isolation). ويتضمن هذا من الأشياء الأخرى، أن تنفّذ التطبيقات في منعزل عن بقيّة بيئة المضيف ولا يمكنها الهروب من البيئة المنعزلة دون المرور عن طريق API. أمثلة عمليّة WebAssembly مثال على WebAssembly هو Enarx. يوفّر مشروع Enarx استقلاليّة الأجهزة لتأمين التطبيقات باستخدام بيئات التنفيذ الموثوق (Trusted Execution Environments)، فيسمح لك هذا الأخير بتسليم تطبيق مترجم إلى WebAssembly بشكل آمن إلى مزود السحابي (cloud) وتشغيله عن بعد، وكما يقول مهندس الأمن في Red Hat المهندس Nathaniel McCallum: ومثال آخر لذلك هو OPA أي عميل السياسة المفتوحة (Open Policy Agent)، والذي أعلن في نوفمبر 2019 أنه يمكنك ترجمة لغة تعريف السياسة الخاصة بهم Rego إلى WebAssembly، يسمح لك Rego بكتابة المنطق للبحث والجمع بين بيانات JSON/YAML من مختلف المصادر لسؤال عن أسئلة مثل "هل API هذا متاح؟". أستخدمت OPA لتطبيقات تفعيل السياسة (policy-enable software) والتي من بينها Kubernetes، ويُعتبر تبسيط السياسة باستخدام أدوات مثل OPA خطوة مهمة لتأمين نشر Kubernetes بشكل جيّد بين البيئات المختلفة، فمحمولية وميزات الأمن المدمجة في WebAssembly تعتبر أسلحة ممتازة لهذه الأدوات. آخر مثال على ذلك هو Unity، لقد ذكرنا في بداية المقال عن أنه WebAssembly يُستخدم في الألعاب، فيعتبر يونتي Unity والذي هو محرّك ألعاب متعدّد المنصات من أوائل المتبنين للـ WebAssembly، حيث وفروا أول نسخة تجريبيّة لـ Wasm في المتصفحات، ومنذ الشهر الثامن من سنة 2018، تُستخدم WebAssembly كهدف للمخرجات لهدف بناء Unity WebGL. نظرة أعمق على WebAssembly إن WebAssembly هو ملف ثنائي يمكن تشغيله من قبل جميع المتصفحات (باستثناء IE 11) عبر الأجهزتها الافتراضيّة، ولديه القدرة على البدء والعمل بشكل أسرع من جافا سكربت لأن الملف الثنائي يمكن فهمه بسهولة من قبل المتصفحات وسيعمل بطريقة مثاليّة، وإذا كنت مهتم بالتفاصيل التقنيّة التي تجعل من WebAssembly مميّز، فأنصحك بهذا المقال. وعلى الرغم من أنني بدأت بالبحث في WebAssembly عند بحثي عن طريقة كتابة Rust في بيئات أخرى (على سبيل المثال المتصفّح)، لكن ليس هذا ما يجعل WebAssembly مميّز، فأنا أستمتع بكتابة جافا سكربت (TypeScript على وجه الخصوص)، وبيئة تطوير الويب المبنيّة على جافا سكربت كبيرة للغاية ولا يمكن إلغاؤها، فيمكنك اعتبار WebAssembly كإضافة إلى جافا سكربت حيث يمكنك استخدامه في المهام التي يكون أداء جافا سكربت ضعيف. يمكن استخدام WebAssembly لكتابة تطبيقات ويب كاملة أو استبدال أجزاء من تطبيقات يكون أدائها غير جيّد كفاية ببديل يعمل بسرعة أكبر، وبالإضافة إلى ذلك، بما أن WebAssembly ملف تجميع مشابه للغة الآلة، فيمكن استخدام العديد من اللغات للترجمة إليه، أي مشاركة الشيفرة البرمجية مع المنصات الأخرى والويب أصبح الآن أكثر عملية. لغات تدعم WebAssembly يمكن استخدام العديد من اللغات للترجمة إلى WebAssembly، بما في ذلك C#‎ وGo، فلماذا لا نستخدمهم بدلًا من Rust؟ على الرغم من أن استخدام لغات البرمجة هو أمر شخصي يختلف حسب تفضيلات الشخص، إلا أن هنالك العديد من الأسباب التي تجعل من Rust أفضل أداة لهذا العمل، فهذه اللغات تملك وقت تشغيل كبير يجب وضعه في ملف الثنائي لـ WebAssembly، لذلك فهي مناسبة فقط للمشاريع الجديدة غير المبنيّة على مشاريع أخرى (على سبيل المثال، فهي مناسبة كبديل لجافا سكربت)، هذا المقال ستجد في قسم Wasm في ويكي لغة GO يقول أن أصغر حجم ملف ثنائي غير مضغوط يمكن عمله هو 2 ميغابايت، بالنسبة للغة Rust، والتي تملك أجزاء وقت التشغيل صغيرة للغاية (مجرّد allocator)، فمثال "أهلا بالعالم" يُترجم إلى ملف بحجم 1.6 كيلوبايت على حاسوبي بدون تحسينات لخفض الحجم (والتي يمكنها تصغيره أكثر). أنا لا أقول أن للغات Go وC#‎ مستقبل سيء بالنسبة لتطبيقات الويب، فأنا متشوّق حول جديدها، لكنني أعتقد أنها ستكون مناسبة للمشاريع الجديدة غير مبنيّة على مشاريع أخرى. على الرغم من أن لغات C و C++‎ تملك وقت تشغيل صغير للغاية مثل Rust وهي مناسبة لوضعها داخل التطبيقات والمكتبات الموجودة بالفعل، فإن Rust ستجعل من إنشاء ملفات WebAssembly ثنائيّة التي تستخدم واجهات جافا سكربت اصطلاحيّة إلى حد ما باستخدام الأدوات التي سنكتشفها في المقالات هذه السلسلة، في حين أن المعالجة في لغات C و C++‎ أكثر يدويّة. إن استخدام الأدوات في لغة Rust جميل للغاية وأعتقد أنها تجعل كامل التجربة ممتعة بشكل أكبر، وتمتاز لغة Rust بأنها لغة آمنة للذاكرة لذا فإن هذا الصنف من الأخطاء الموجودة في لغات C و C++‎ يستحيل وجوده في Rust، وإذا استخدمت لغات تملك ذاكرة آمنة مثل جافا سكربت وجافا وC#‎ (وحتى إذا لم تستخدمها) سترغب باستخدام لغة Rust. لنسمي لغات C و C++‎ و Rust بلغات النظام، لأن هدفهم برمجة الأنظمة وتطبيقات عاليّة الأداء. تتشارك هذه اللغات بمميزات تجعلهم منسابين للترجمة إلى WebAssembly، سنتعرف في القسم القادم على المزيد من التفاصيل وسنعد أمثلة لشيفرات برمجية كاملة بلغات C و TypeScript مع عينات من لغة صيغة نص WebAssembly. أنواع البيانات الصريحة وجامع القمامة تتطلّب لغات الأنظمة أنواع بيانات صريحة مثل int وdouble للتصريح عن متغيرات القيم المرجعة من الدوال، فعلى سبيل المثال، توضح هذه الشيفرة البرمجية عملية جمع 64 بت في لغة السي: long n1 = random(); long n2 = random(); long sum = n1 + n2; دوال المكتبة random تعرّف نوع long للإرجاع: long random(); /* returns a long */ في أثناء الترجمة، تتحول الشيفرة المكتوبة بلغة C إلى لغة التجميع (أسمبلي) ومن ثم إلى لغة الآلة، تتحول الشيفرة البرمجيّة السابقة في لغة التجميع لـ Intel (نوع AT&T)، إلى ما يشبه هذا (حيث أن ## هي التعليقات): addq %rax, %rdx ## %rax = %rax + %rdx (64-bit addition) إن ‎%‎rax و ‎%‎rdx هي سجلات 64 بت، وتعليمة addq تعني أجمع quadwords، حيث أن quadwords هي 64 بت، والذي هو المعيار لنوع long في لغة سي، تترجم لغة التجميع التعليمات السابقة إلى لغة الآلة بما في ذلك الأنواع، حيث أن في العادة يقدم النوع من خلال خليط بين التعليمات والمعاملات، وفي هذه الحالة، تعليمة add هي addq (عملية جمع 64 بت)، وهنالك أيضًا addl والتي تجمع قيم 32 بت، أي نوع int في لغة السي. السجلات هي من نوع 64 بت (حرف r في ‎%rax و ‎%rdx) بدلًا من قطع 32 بت منه (على سبيل المثال ‎%eax هو النسخة المنخفضة من 32بت من ‎%rax و ‎%edx هي النسخة 32بت المنخفضة من ‎%rdx). تنفّذ عملية الجمع في لغة التجميع بأداء عالي لأن المعاملات مخزنة في سجلات CPU، ومترجم لغة C العادي (حتى لو استخدم تحسينات الوضع الافتراضي) سينتج شيفرة برمجيّة بلغة أسمبلي مشابهة للسابق. تعتبر لغات الأنظمة الثلاثة هي خيارات جيّدة للترجمة إلى WebAssembly بسبب تركيزها على أنواع صريحة كما في WebAssembly: i32 لقيمة عدد صحيح 32 بت و f64 لقيمة الفاصلة العائمة، وهكذا… تشجع أنواع البيانات الصريحة تحسين استدعاءات الدالة، فتملك الدالة مع نوع بيانات صريح توقيع يحدد أنواع البيانات للمعاملات والقيمة التي ستعود من الدالة (إذا كانت موجودة)، وفي الأسفل توقيع لدالة WebAssembly تسمى ‎$add، وهي مكتوبة بشكل نص لغة WebAssembly كما سنتحدث عليها لاحقًا، تأخذ الدالة عددين صحيحين 32 بت كمعاملات وترجع عدد صحيح 64 بت: (func $add (param $lhs i32) (param $rhs i32) (result i64)) يجب أن يملك مترجم JIT للمتصفح على معاملات أعداد صحيحة 32 بت ويرجع قيمة 64 بت مخزنة في سجلات بالحجم المناسب. عندما نتحدث عن شيفرة برمجيّة عالية الأداء فإن WebAssembly تتربع على عرش ذلك، فعلى سبيل المثال asm.js هي لغة برمجة مشابهة لجافا سكربت لزيادة الأداء وجعلها مقاربة لسرعة الآلة، فتدعو هذه اللغة إلى تحسين الشيفرة البرمجيّة لتحاكي أنواع البيانات الصريحة الموجودة في لغات النظام، هذا المثال بلغة C وآخر بلغة asm.js، فعينة الدالة في لغة C هي: int f(int n) { /** C **/ return n + 1; } فكل من معامل n و نوع الإرجاع من نوع int بصراحة، والدالة المقابلة لذلك في asm.js ستكون هذه : function f(n) { /** asm.js **/ n = n | 0; return (n + 1) | 0; } فلغة جافا سكربت لا تعلن صراحة عن أنواع البيانات، لكن عملية OR بتيّة في جافا سكربت ترجع عدد صحيح، هذا مثال لعملية OR البتيّة عديمة الجدوى: n = n | 0; /* bitwise-OR of n and zero */ عمليّة OR البتيّة بين n و صفر تساوي n، لكن هدفنا هنا أن n يحتوي على عدد صحيح، فتعليمة return تخدعك عن طريق التحسين. يتميّز TypeScript بين أنواع جافا سكربت بتبني أنواع البيانات الصريحة، والتي ستجعل من هذه اللغة جذابة للترجمة إلى لغة WebAssembly (ستجد شيفرة برمجية تفسر هذا في الأسفل). الميّزة المشتركة الثانية بين أنظمة اللغات الثلاثة أنها تنفّذ دون جامع القمامة garbage collector (GC)‎، فمترجم لغة Rust لتخصيص الذاكرة بشكل حيوي يكتب شيفرات البرمجيّة الخاصة بالتخصيص وإلغاء التخصيص (allocation/deallocation) وبالنسبة لبقية اللغات، يقع هذا العمل على المبرمج حيث أن من مهامه تخصيص وإلغاء التخصيص بشكل صريح في هذه الذاكرة، لذلك فلغات الأنظمة تتجنّب تعقيدات جامع القمامة التلقائي. يمكن تلخيص ما عرفناه على WebAssembly في أن أي مقال على لغة WebAssembly تقريبًا يذكر سرعته القريبة من سرعة الآلة كأهم ميزة فيه، لذلك فإن هذه اللغات الثلاثة كانوا أول مشرحين للترجمة إلى WebAssembly. فصل المخاوف بين جافا سكربت و WebAssembly على عكس جميع الإشاعات، فلقد صممت لغة WebAssembly لدعم جافا سكربت وليس لاستبداله عن طريق توفير أداء أفضل في المهام الصعب، ولهذه اللغة أفضلية عند التنزيل، فالمتصفح يحصل على وحدة جافا سكربت كنص، وفي WebAssembly يحصل على صيغة ثنائيّة مضغوطة لتسريع التنزيل. من المهم معرفة كيف جافا سكربت وWebAssembly يعملان معًا، فجافاسكربت مصمم لقراءة وكتابة نموذج كائن المستند (Document Object Model - DOM)، الشجرة التي تمثل صفحة الويب، وعلى نقيض ذلك، لا يأتي WebAssembly على أي وظائف مدمجة لـ DOM، لكن يمكن لـ WebAssembly استيراد الدوال من جافا سكربت واستدعاءها حسب الحاجة، يفسر هذا كيفية عمل ذلك: DOM<----->JS<----->WebAssembly سيبقى جافا سكربت في أي نوع من أنواعه يدير DOM، لكن يمكنه استخدام وظائف الأغراض العامة من وحدات WebAssembly، كما في الشيفرة البرمجية السابقة. تسلسل Hailstone وتخمين Collatz هنالك أمثلة عديدة لشيفرة WebAssembly في وضع الإنتاج عند عملها بأداء عالي، مثل إنشاء أزواج مفاتيح تشفير كبيرة أو استخدام هذه المفاتيح للتشفير وفك تشفير، ومثال على ذلك يمكن اتباعه بسهول، هنالك عملية صعبة بأعداد كبيرة ويمكن لجافا سكربت التعامل معها بسهولة. هذه دالة hstone (اختصار لـ Hailstone)، تأخذ عدد صحيح كمعامل. تعريف هذه الدالة كالتالي: 3N + 1 إذا كان N عدد فردي hstone(N) = N/2 إذا كان N عدد زوجي على سبيل المثال، hstone(12)‎ ترجع 6 في حين hstone(11)‎ ترجع 34، إذا كان N عدد فردي، فإن 3N+1 هو عدد زوجي، وإذا كان N عدد زوجي، فإن N/2 إما عدد زوجي (مثال 4/2=2) أو فردي (مثال 6/2=3). يمكن استخدام دالة hstone بطريقة عودية عن طريق تمرير قيمة العودة كالمعامل التالي، وستكون النتيجة هي تسلسل hailstone مثل هذه، والتي تبدأ برقم 24 كمعامل أول، وترجع القيمة 12 كمعامل التالي وهكذا: 24,12,6,3,10,5,16,8,4,2,1,4,2,1,... يتطلب الأمر 10 استدعاءات للدالة حتى تستقر على الرقم واحد، وسيبقى التسلسل 4,2,1 يتكرر إلى ما لا نهاية لأن (3x1)+1 هو 4، لذلك يقسم على 2 ليعود 2، والذي يقسم على 2 ليكون 1 وهكذا دواليك، ولمزيد من المعلومات يمكنك الإطلاع على تفسير مجلة Plus حول لماذا اسم hailstone هو الاسم المناسب لهذا التسلسل. لاحظ أن أس 2 تتلاقى بسرعة كبيرة، حيث أنها تتطلّب N تقسيمات على 2 للوصول إلى 1، فعلى سبيل المثال 32 = 25 لديها طول تقارب 5 و 64 = 26 لديها طول تقارب 6 ، نهتم هنا بطول التسلسل من المعامل الأول إلى أول ظهور لرقم 1، فشيفرتي البرمجية بلغة C و TypeScript تحسب طول تسلسل hailstone. تخمين Collatz هو تسلسل hailstone يتقارب إلى 1 مهما كان المعامل N>0، فلم يستطع أحد تفنيد تخمين Collatz ولم يتمكن أي أحد الحصول على إثبات لجعل التخمين نظرية، فالتخمين، على الرغم من سهولة تجربته ببرنامج، يبقى مشكلة صعبة في الرياضيات. من C إلى WebAssembly في خطوة واحدة برنامج hstoneCL أسفله هو تطبيق ليس ويب يمكن ترجمته باستخدام مترجم Cعادي (على سبيل المثال GNU أو Clang)، يولّد هذا البرنامج عدد صحيح عشوائي قيمته N>0 ثمانية مرات ويحسب طول تسلسل hailstone بداية من N، دالتين مهمتين وهما main وhstone عند ترجمة التطبيق إلى WebAssembly. المثال 1 - دالة hstone في لغة السي #include <stdio.h> #include <stdlib.h> #include <time.h> int hstone(int n) { int len = 0; while (1) { if (1 == n) break; /* halt on 1 */ if (0 == (n & 1)) n = n / 2; /* if n is even */ else n = (3 * n) + 1; /* if n is odd */ len++; /* increment counter */ } return len; } #define HowMany 8 int main() { srand(time(NULL)); /* seed random number generator */ int i; puts(" Num Steps to 1"); for (i = 0; i < HowMany; i++) { int num = rand() % 100 + 1; /* + 1 to avoid zero */ printf("%4i %7i\n", num, hstone(num)); } return 0; } يمكن ترجمة الشيفرة البرمجية وتشغيلها من سطر الأوامر (حيث أن % موجه لسطر الأوامر) على أي نظام مشابه ليونكس: % gcc -o hstoneCL hstoneCL.c ## compile into executable hstoneCL % ./hstoneCL ## execute هذا مثال لمخرجات عند التشغيل: Num Steps to 1 88 17 1 0 20 7 41 109 80 9 84 9 94 105 34 13 تتطلّب لغات الأنظمة (بما في ذلك لغة السي) أداة مخصصّة لترجمة الشيفرة البرمجية إلى وحدة WebAssembly، بالنسبة للغات C وC++‎، يعتبر Emscripten هو الخيار الأكثر الانتشارًا مبني على بنية مترجم LLVM (Low-Level Virtual Machine)‎، استخدمت في امثلتي بلغة C على EmScripten، والذي يمكنك تثبيته بمساعدة هذا الدليل. يمكن جعل برنامج hstoneCL يعمل على الويب باستخدام Emscription لترجمة الشيفرة البرمجيّة - دون تغيير - إلى وحدة WebAssembly، تُنشئ أداة Emscription صفحة HTML مع جافا سكربت (في asm.js) الذي يتوسط بين DOM ووحدة WebAssembly التي تحسب دالة hstone، وهذه هي الخطوات: 1- ترجمة برنامج hstoneCL الذي لا يعمل على الويب إلى WebAssembly: % emcc hstoneCL.c -o hstone.html ## generates hstone.js and hstone.wasm as well يحتوي ملف hstoneCL.c على الشيفرة البرمجيّة الموجودة في الأعلى، و معامل ‎-o لراية المخرجات والتي ستحدد اسم ملف HTML وسيحمل كل من شيفرة جافا سكربت المولّدة وملف ثنائي WebAssembly نفس الاسم (في هذه الحالة، hstone.js و hstone.wasm على التوالي)، النسخ الأقدم من Emscription (قبل الاصدار 13)، قد يتطلّب تضمين راية -s WASM=1 في أمر الترجمة. 2- استخدم خادم ويب Emscription (أو ما يعادله) لاستضافة تطبيق الويب: % emrun --no_browser --port 9876 . ## . is current working directory, any port number you like لتجاوز رسائل التحذيريّة، يمكنك تضمين راية ‎--no_emrun_detect. يشغّل هذا الأمر خادم الويب، والذي يستضيف جميع الموارد في مجلد العمل الحالي، على وجه الخصوص hstone.html و hstone.js و hstone.wasm. 3- افتح المتصفح مع تفعيل WebAssembly (على سبيل المثال Chrome أو Firefox) وانتقل إلى العنوان : http://localhost:9876/hstone.html. تظهر هذه الصورة المخرجات من حاسوبي باستخدام متصفح Firefox: النتيجة رائعة خاصة أنك كتبت سطر واحد فقط دون أي تغييرات على برنامج C الأصلي. تحسين برنامج hstone للويب تترجم أداة Emscription برنامج C إلى وحدة WebAssembly وتولّد جافا سكربت المطلوب، لكن هذه الأداة مناسبة لشيفرة برمجيّة ولّدتها اللآلة، على سبيل المثال، ينتج asm.js ملف بحجم 100 كيلوبايت تقريبًا، تتعامل شيفرة البرمجيّة للجافا سكربت عدة سيناريوهات ولا تستخدم API الأخير الخاص بـ WebAssembly. نسخة مصغّرة من برنامج hstone للويب ستجعل من السهل التركيز على كيف تتعامل وحدة WebAssembly (الموجودة في ملف hstone.wasm) مع جافا سكربت (الموجود في ملف hstone.js). هنالك مشكلة أخرى: الشيفرة البرمجيّة لـ WebAssembly لا تملك حدود دالية في مصدر البرنامج كما في لغة السي، فعلى سبيل المثال، يملك برنامج ChstoneCL دالتين معرفتين من قبل المستخدم وهما main و hstone، ستكون النتيجة تصدير وحدة WebAssembly دالة تسمى ‎_main لكنها لا تصدر دالة اسمها ‎_hstone (حيث أن دالة main هي نقطة الدخول في برنامج سي). جسم دالة Chstone سيكون في دالة غير مصدّرة أي ملفوفة بـ ‎_main، دوال WebAssembly المصدّرة هي نفسها التي يمكن لجافا سكربت استدعاؤها باسمها، وعلى الرغم من ذلك، من الأفضل تحديد أي دوال لغة المصدر يجب تصديرها بالاسم في شيفرة البرمجيّة لـ WebAssembly. المثال الثاني - برنامج hstone المنقح #include <stdio.h> #include <stdlib.h> #include <time.h> #include <emscripten/emscripten.h> int EMSCRIPTEN_KEEPALIVE hstone(int n) { int len = 0; while (1) { if (1 == n) break; /* halt on 1 */ if (0 == (n & 1)) n = n / 2; /* if n is even */ else n = (3 * n) + 1; /* if n is odd */ len++; /* increment counter */ } return len; } برنامج hstoneWA المنقح المعروض أعلاه، لا يملك دالة main، فلا حاجة له، لأن البرنامج ليس مصمم للعمل كبرنامج مستقل بل مخصص لوحدة WebAssembly مع دالة تصدير واحدة. يشير توجيه EMSCRIPTEN_KEEPALIVE (المعرّف في الملف الرأCemscripten.h) إلى المترجم لتصدير دالة ‎_hstone في وحدة WebAssembly، إتفاقية الاسم واضحة للغاية: يبقى اسم دالة Cمثل hstone، لكن مع شرطة السفليّة كحرف أول في WebAssembly (أي ‎_hstone في هذه الحالة)، وتتبع مترجمات WebAssembly أخرى اتفاقيات أسماء مختلفة. للتأكد من عمل ذلك، يمكنك اختصار خطوة الترجمة إلى إنتاج وحدة WebAssembly و جافا سكربت، لكن بدون HTML: % emcc hstoneWA.c -o hstone2.js ## we'll provide our own HTML file يمكن اختصار الملف HTML إلى هذا: <!doctype html> <html> <head> <meta charset="utf-8"/> <script src="hstone2.js"></script> </head> <body/> </html> يحمل ملف HTML ملف جافا سكربت، والذي يقوم بجلب وتحميل ملف WebAssembly الثنائي الذي يسمى hstone2.wasm، وبالمناسبة ملف WASM الجديد بنصف حجم الملف الأصلي تقريبًا. يمكن ترجمة الشيفرة البرمجية للتطبيق كالسابق ومن ثم تشغيله مع خادم الويب المدمج: % emrun --no_browser --port 7777 . ## new port number for emphasis بعد طلب وزيارة ملف HTML في المتصفح (في هذه الحالة Chrome)، يمكن استخدام كونسول ويب للتأكّد من تصدير دالة hstone على أنها ‎_‎‎hstone. هذا مقتطف من جلستي في كونسول الويب، مع ## للتعليقات: > _hstone(27) ## invoke _hstone by name < 111 ## output > _hstone(7) ## again < 16 ## output يعتبر استخدام موجه EMSCRIPTEN_KEEPALIVE هو طريقة واضحة لجعل مترجم Emscripten وحدة WebAssembly تصدّر أي دالة إلى جافا سكربت، وهذا ما يقوم به هذا المترجم، وأي مستند HTML مخصّص مع جافا سكربت يدوي مناسب يمكنه استدعاء دوال من وحدة WebAssembly وذلك بفضل Emscripten. ترجمة TypeScript إلى WebAssembly مثال شيفرة البرمجيّة التالية بلغة TypeScript، والتي هي جافا سكربت مع أنواع بيانات صريحة، ويتطلب هذا Node.js مع مدير الحزم الخاص به npm، يثبت أمر npm التالي AssemblyScript والذي هو مترجم WebAssembly لشيفرة برمجية TypeScript: % npm install -g assemblyscript ## install the AssemblyScript compiler يتكون برنامج TypeScript hstone.ts من دالة واحدة، والتي تسمى hstone أيضًا، وسيسبق نوع البيانات i32 (عدد صحيح 32 بت) المعاملات وأسماء المتغيرات المحليّة (في هذه الحالة، n و len على التوالي): export function hstone(n: i32): i32 { // will be exported in WebAssembly let len: i32 = 0; while (true) { if (1 == n) break; // halt on 1 if (0 == (n & 1)) n = n / 2; // if n is even else n = (3 * n) + 1; // if n is odd len++; // increment counter } return len; } تأخذ دالة hsotne معامل واحد من نوع i32 وترجع قيمة من نفس النوع، ويشبه جسم الدالة ذلك الموجود في مثال لغة سي، ويمكن ترجمة الشيفرة المصدريّة إلى WebAssembly كالتالي: % asc hstone.ts -o hstone.wasm ## compile a TypeScript file into WebAssembly حجم ملف WASM hstone.wasm حوالي 14 كيلوبايت. لإيضاح كيف تحمّل وحدة WebAssembly، يتضمن ملف HTML في الأسفل (index.html في موقعي) سكربت جلب وتحميل وحدة WebAssembly hstone.wasm ومن ثم إنشاء مثيل لهذه الوحدة حتى يمكن استدعاء دالة hstone في كونسول المتصفح. المثال 3 - صفحة HTML لشيفرة TypeScript <!doctype html> <html> <head> <meta charset="utf-8"/> <script> fetch('hstone.wasm').then(response => <!-- Line 1 --> response.arrayBuffer() <!-- Line 2 --> ).then(bytes => <!-- Line 3 --> WebAssembly.instantiate(bytes, {imports: {}}) <!-- Line 4 --> ).then(results => { <!-- Line 5 --> window.hstone = results.instance.exports.hstone; <!-- Line 6 --> }); </script> </head> <body/> </html> يمكن تفسير عنصر script في HTML السابق سطرً سطرًا، فيستخدم استدعاء fetch في السطر الأول وحدة fetch للحصول على وحدة WebAssembly من خادم الويب الذي يستضيف صفحة HTML، وعند وصول إجابة HTTP، ستعمل وحدة WebAssembly كتسلسل من البيتات، والتي ستكون مخزّنة في arrayBuffer من السكربت في السطر 2، تتكوّن هذه البايتات من وحدة WebAssembly، والتي هي كامل الشيفرة البرمجيّة مترجمة من ملف TypeScript، هذه الوحدة لا تملك أي استدعاءات، كما هو مبيّن في نهاية السطر 4. في بداية السطر الرابع، سينشئ مثيل وحدة WebAssembly وتشبه هذه الوحدة لصنف غير ثابت مع أعضاء غير ثابتين في لغة كائنيّة التوجه مثل جافا. تحتوي الوحدة من متغيرات، دوال، وأدوات دعم مختلفة (artifacts)، لكن يجب إنشاء مثيل للوحدة قبل استخدامها كما في الصنف غير ثابت، وفي هذه الحالة في كونسول الويب، لكن بصفة عامة في شيفرة جافاسكربت مناسبة. يصدّر السطر السادس من السكربت دالة hstone من TypeScript الأصليّة بنفس الاسم، وستكون دالة WebAssembly متاحة لأي شيفرة جافا سكربت، كما ستؤكد جلسة أخرى في كونسول المتصفح. يملك WebAssembly API أكثر إيجازًا لجلب وإنشاء مثيل وحدة، يقلل API الجديد السكربت السابق لعمليتي جلب وإنشاء مثيل، بالنسبة إلى النسخة التي عرضناها هنا لإيضاح فائدة التفاصيل، وبشكل خاص، عرض وحدة WebAssembly كمصفوفة بايت التي ينشئ مثيلها ككائن مع دوال المصدّر. الهدف هو الحصول على صفحة ويب تحمّل وحدة WebAssembly بنفس طريقة وحدة JS ES2015: <script type='module'>...</script> سيعمل جافا سكربت على جلب وترجمة ومعالجة وحدة WebAssembly كما لو كانت مجرّد واحدة JS أخرى. لغة صيغة النص (text format language) يمكن ترجمة الشيفرة الثنائيّة لـ WebAssembly من وإلى مرادفها بصيغة النص، فالشيفرة الثنائيّة تكون موجودة في ملفات بصيغة WASM، في حين أن نصوص قابلة للقراءة من قبل المبرمجين تكون موجودة بملفات بصيغة WAT. إن WABT هي مجموعة من عشرات الأدوات للتعامل مع WebAssembly، بما في ذلك للترجمة من وإلى صيغ مثل WASM و WARK ومن بين أدوات التحويل wasm2wat و wasm2c و wat2wasm. تتبنى لغة صيغة النص صياغة ‎S-expression‎ ‎(S تعني رمزي symbolic) الشائعة في Lisp، تمثل S-expression واختصارها sexpr شجرة كقائمة مع العديد من القوائم الفرعية بشكل اعتباطي، فعلى سبيل المثال، يحدث هذا sexpr بالقرب من نهاية ملف WAT لمثال TypeScript: (export "hstone" (func $hstone)) ## export function $hstone by the name "hstone" الشجرة التي تمثله هي التاليّة: export ## root | +----+----+ | | "hstone" func ## left and right children | $hstone ## single child في الصيغة النصيّة، وحدة WebAssembly هي sexpr حيث أن الجزء الأول هي الوحدة module والتي هي جذر الشجرة. هذا مثال ثاني لوحدة معرّفة ومصدّرة كدالة فرديّة، والتي لا تأخذ أي معامل لكنها ترجع ثابت 9876: (module (func (result i32) (i32.const 9876) ) (export "simpleFunc" (func 0)) // 0 is the unnamed function's index ) تعرّف هذه الدالة دون اسم (كما في lambda) وتصدّر بالإشارة إلى مؤشر 0، والذي هو مؤشر أول sexpr متداخل في الوحدة، وإن اسم دالة التصدير هي السلسلة النصيّة "simpleFunc". الدوال في صيغة النص تملك نمط قياسي، والذي يمكن تفسيره على النحو التالي: (func <signature> <local vars> <body>) يحدّد التوقيع المعاملات (إذا كانت موجودة) ويرجع قيمة العودة (إذا كانت موجودة)، فعلى سبيل المثال، هذا توقيع لدالة لا تملك اسم تأخذ معاملين من نوع عدد صحيح 32 بت وتعيد قيمة عدد صحيح 64 بت: (func (param i32) (param i32) (result i64)...) يمكن إعطاء الأسماء إلى الدوال والمعاملات والمتغيرات المحليّة، حيث يبدأ الأسم بعلامة دولار: (func $foo (param $a1 i32) (param $a2 f32) (local $n1 f64)...) يعكس جسد دالة WebAssembly بنية الآلة الأساسية لهذه اللغة، فتخزين المكدس هو الأساس، ومثال ذلك دالة تضاعف معامل عددها الصحيح وتعيد القيمة الجديدة: (func $doubleit (param $p i32) (result i32) get_local $p get_local $p i32.add) تدفع كل واحدة من عمليات get_local، والتي تعمل على المتغيرات المحلية والمعاملات المشابهة، معامل 32 بت إلى المكدس، وستخرج عملية i32.add أعلى قيمتين (والتي هي في هذه الحالة، القيم الوحيدة) من المكدس بجمعهم، وستكون النتيجة هي القيمة الوحيدة الموجودة في المكدّس وبالتالي سترجع من دالة ‎$doubleit. عند ترجمة شيفرة WebAssembly إلى لغة الآلة، يجب استبدال أساس مكدس WebAssembly عند الإمكان بسجلات الأغراض العامة، وهذه مهمة مترجم JIT، والتي تترجم شيفرة آلة المكدس الافتراضية لـ WebAssembly إلى شيفرة آلة حقيقيّة. لا يفضل مبرمجو الويب كتابة WebAssembly بصيغة النص، حيث أن الترجمة من لغة عالية المستوى يعتبر خيار أفضل لهم على عكس كتّاب المترجم، حيث سيجدون من المفيد العمل عليها. الخاتمة على الرغم من إحراز الكثير من هدف WebAssembly للوصول إلى سرعة مقاربة لآلة (Native)، لكن لايزال مترجم JIT لجافا سكربت يتحسن مع ظهور أنواع مناسبة للتحسين (مثل TypeScript) تقترب من سرعة الآلة (native)، فهل هذا يعني أن WebAssembly هو مضيعة للوقت؟ لا أعتقد ذلك. يعالج WebAssembly هدفًا تقليديًا آخر في الحوسبة: إعادة استخدام الشيفرة البرمجية ذات معنى، كما توضح الأمثلة المختصرة في هذا المقال، فإن الشيفرة البرمجيّة بلغة C أو TypeScript، تترجم بسهولة إلى وحدة WebAssembly والتي تعمل بشكل جيّد مع شيفرة برمجيّة خاصة بجافا سكربت وهو الرابط بين التقنيات المستخدمة في الويب، وبالتالي يدعو WebAssembly إلى إعادة استخدام الشيفرة البرمجيّة وتوسيع استخدام التعليمات الجديدة، على سبيل المثال، قد يكون برنامج عالي الأداء لمعالجة الصور مكتوب كتطبيق سطح المكتب مفيدًا أيضا في تطبيق ويب، لذلك سيكون من الأفضل استخدام WebAssembly (بالنسبة لوحدات الويب الجديدة ذات صلة بالحسابات، سيكون WebAssembly هو خيار جيّد). وحدسي يقول أن WebAssembly ستزدهر بنفس القدر لإعادة استخدام للأداء. ترجمة -وبتصرف- للمقالات: WebAssembly for speed and code reuse لصاحبه Marty Kalin Why everyone is talking about WebAssembly لصاحبيه Gordon Haff وMike Bursell Why should you use Rust in WebAssembly? لصاحبه Ryan Levick
  2. مع انتقال أدوات المطورين إلى السحاب (cloud)، يزداد عدد المتبنين لمنصات بيئة تطوير متكاملة IDE ‏(Integrated Development Environment بيئة التطوير المتكاملة) السحابيّة، فهذه المنصات يمكن الوصول إليها من أي نوع من الأجهزة الحديثة عن طريق المتصفحات، وهي توفّر مميزات مهمة عند التعاون في الوقت الحقيقي، فيوفر العمل في منصة IDE سحابيّة بيئة موحدّة للتطوير والتجربة لك ولفريقك مع تقليل مشاكل عدم توافق المنصات، فيمكنك الوصول إليها من أي نوع من الأجهزة الحديثة عن طريق المتصفحات. فـ Eclipse Theia هي منصة IDE سحابيّة قابلة للتوسع تعمل على خادم عن بعد ويمكن الوصول إليها من متصفح الويب، وشكلها يشبه Microsoft Visual Studio Code وتدعم العديد من لغات البرمجة ولديها تصميم مرن وطرفيّة (Terminal)، وما يفرّق بين Eclipse Theia من بقيّة برامج IDE السحابيّة هي قابليّة تخصيصها وزيادة مميزاتها باستخدام الملحقات المخصّصة، والتي تسمح لك بتعديل IDE السحابي حسب رغباتك. سننشر في هذا الدرس Eclipse Theia إلى خادم أوبنتو 18.04 باستخدام Docker Compose والتي هي أداة لمزامنة الحاوية، والتي ستكشفها في اسم النطاق الخاص بك باستخدام nginx-proxy والذي هو نظام تلقائي لـ Docker يبسط عملية إعداد Nginx ليعمل كوكيل عكسي (reverse proxy) للحاوية، وستأمنها باستخدام شهادة Let’s Encrypt TLS عن طريق الملحق المخصص لها. وفي النهاية ستحصل على Eclipse Theia يعمل على خادم أوبنتو 18.04 متوفّر عن طريق HTTPS يمكن للمستخدم تسجيل دخوله ليبدأ العمل عليه. المتطلبات الأساسية خادم أوبنتو 18.04 مع صلاحيات الجذر بالإضافة إلى حساب آخر عادي ليس جذر، يمكنك اعداد ذلك عن طريق اتباع هذا الدرس بالنسبة لهذا المقال، المستخدم العادي (ليس جذر) هو sammy. تثبيت Docker على خادمك، يمكنك اتباع الخطوة الأولى والثانية من هذا الدرس وللتعرّف على Docker، يمكنك الإطلاع على هذا الدرس. تثبيت Docker Compose على خادمك، يمكنك اتباع الخطوة الأول من درس تثبيت Docker Compose. اسم نطاق مسجّل بالكامل، سنستخدم في هذا درس theia.your_domain والذي يمكنك استبداله بأي اسم ستشتريه من أي موقع يوفر هذه الخدمة. سِجل DNS مع إشارة theia.your_domain إلى عنوان IP الخادم العام، يمكنك الإطلاع على المقدمة إلى DNS الخاص بـ DigitalOcean للمزيد من التفاصيل. الخطوة الأولى - نشر nginx-proxy مع Let’s Encrypt في هذا القسم، ستنشر nginx-proxy مع إضافة Let's Encrypt باستخدام Docker Compose، وسيفعّل هذا عمليّة تفعيل وتجديد شهادة TLS بشكل تلقائي، لذلك عندما تنشر Eclipse Theia، ستتمكن من الوصول إلى نطاقك عن طريق HTTPS. في هذا الدرس، سنسجل جميع الملفات في ‎~/‎eclipse-theia، أنشئ هذا المجلّد عن طريق تشغيل هذا الأمر: mkdir ~/eclipse-theia انتقل إلى هذا المجلّد عن طريق: cd ~/eclipse-theia يجب عليك حفظ إعدادات Docker Compose لـ nginx-proxy في ملف يسمى nginx-proxy-compose.yaml، أنشئه باستخدام محرّر النصوص الخاص بك: nano nginx-proxy-compose.yaml وأضف الأسطر التاليّة إليه (ملف nginx-proxy-compose.yaml): version: '2' services: nginx-proxy: restart: always image: jwilder/nginx-proxy ports: - "80:80" - "443:443" volumes: - "/etc/nginx/htpasswd:/etc/nginx/htpasswd" - "/etc/nginx/vhost.d" - "/usr/share/nginx/html" - "/var/run/docker.sock:/tmp/docker.sock:ro" - "/etc/nginx/certs" letsencrypt-nginx-proxy-companion: restart: always image: jrcs/letsencrypt-nginx-proxy-companion volumes: - "/var/run/docker.sock:/var/run/docker.sock:ro" volumes_from: - "nginx-proxy" ستعرّف هنا خدمتين سيشغلها Docker Compose وهما nginx-proxy و Let’s Encrypt، بالنسبة إلى الوكيل (proxy)، ستحدّد jwilder/nginx-proxy كصورة وستعرّف منافذ HTTP وHTTPS بالإضافة إلى الأماكن (volumes) التي يمكن الوصول إليها وقت التشغيل. الأماكن (Volumes) هي مجلدات في خادمك التي يمكن للخدمات المعرّفة الوصول إليها، والتي ستستخدمها لاحقًا في إعداد مصادقة المستخدم (user authentication)، ولفعل ذلك، ستستخدم المكان الأول من القائمة والذي سيصل مجلد ‎/etc/nginx/htpasswd المحلي إلى نفس المكان في الحاوية، وفي هذا المجلد، سيتوقع nginx-proxy إيجاد نفس الملف مسمى بنفس النطاق المستهدف، ويحتوي على بيانات تسجيل الدخول لمصادقة المستخدم في شكل htpasswd (username:hashed_password). بالنسبة للإضافة، ستضع اسم الصورة وستسمح بالوصول إلى المقبس socket الخاصة بالـ Docker عن طريق تعريف مكان (Volume)، ومن ثم ستحدد أن هذه الإضافة يجب عليها وراثة الوصول إلى الأماكن المعرّفة لـ nginx-proxy، كلا الخدمتين تملكان خيار restart يحتوي على قيمة always، والتي تأمر Docker بإعادة تشغيل الحاويات في حالة التعطل أو إعادة تشغيل النظام. أغلق الملف بعد حفظه وانشر الإعدادات عن طريق تشغيل الأمر التالي: docker-compose -f nginx-proxy-compose.yaml up -d ستمرر في الأمر السابق، اسم ملف nginx-proxy-compose.yaml إلى المعامل ‎-f لأمر docker-compose والذي يحدد الملف الذي سيعمل، وبعد ذلك، ستمرّر فعل up الذي سيشغّل الحاوية. بالنسبة إلى الراية ‎-d فهي تفعّل الوضع المنفصل (detached mode)، والذي يعني أن Docker Compose سيشغّل الحاويات في الخلفية. المخرجات النهائيّة ستشبه لهذه: Creating network "eclipse-theia_default" with the default driver Pulling nginx-proxy (jwilder/nginx-proxy:)... latest: Pulling from jwilder/nginx-proxy 8d691f585fa8: Pull complete 5b07f4e08ad0: Pull complete ... Digest: sha256:dfc0666b9747a6fc851f5fb9b03e65e957b34c95d9635b4b5d1d6b01104bde28 Status: Downloaded newer image for jwilder/nginx-proxy:latest Pulling letsencrypt-nginx-proxy-companion (jrcs/letsencrypt-nginx-proxy-companion:)... latest: Pulling from jrcs/letsencrypt-nginx-proxy-companion 89d9c30c1d48: Pull complete 668840c175f8: Pull complete ... Digest: sha256:a8d369d84079a923fdec8ce2f85827917a15022b0dae9be73e6a0db03be95b5a Status: Downloaded newer image for jrcs/letsencrypt-nginx-proxy-companion:latest Creating eclipse-theia_nginx-proxy_1 ... done Creating eclipse-theia_letsencrypt-nginx-proxy-companion_1 ... done والآن بعد أن نشرنا nginx-proxy ومرافقه Let's Encrypt باستخدام Docker Compose، سننتقل إلى إعداد Eclipse Theia على نطاقك وتأمينه. الخطوة الثانية - نشر Eclipse Thia في Docker سننشئ في هذا القسم ملف يحتوي على بيانات تسجيل الدخول التي سيستخدمها المستخدم، ومن ثم سننشر Eclipse Theia إلى خادمك باستخدام Docker Compose وسنعرضه على نطاقك الآمن باستخدام nginx-proxy. كما شرحنا في الخطوة السابقة، يتوقع nginx-proxy الحصول على بيانات تسجيل الدخول في ملف على النطاق المكشوف على شكل htpasswd ومحفوظة في مجلد ‎/etc/nginx/htpasswd في الحاوية، لا يحتاج المجلد المحلي الذي يشير إلى المجلد الافتراضي أن يكونا نفس الملف، كما حدّدنا في إعدادات nginx-proxy. لإنشاء مجموعات بيانات تسجيل الدخول، ستحتاج أولًا إلى تثبيت htpasswd عن طريق تشغيل الأمر التالي: sudo apt install apache2-utils تحتوي حزمة apache2-utils على أداة htpasswd. أنشئ مجلد ‎/etc/nginx/htpasswd عن طريق الامر التالي: sudo mkdir -p /etc/nginx/htpasswd وأنشئ ملف الذي سيحتوي على بيانات تسجيل الدخول لنطاقك: sudo touch /etc/nginx/htpasswd/theia.your_domain تذكر استبدال theia.your_domain بنطاق Eclipse Theia. لإضافة زوج اسم تسجيل الدخول وكلمة المرور، نفّذ الأمر التالي: sudo htpasswd /etc/nginx/htpasswd/theia.your_domain username استبدل username باسم المستخدم الذي ترغب في إضافته، وسيسألك مرتين عن كلمة المرور، وبعد ذلك سيضيف htpasswd اسم المستخدم وكلمة المرور المشفرة (hashed password) إلى نهاية الملف، يمكنك إعادة هذا الأمر بعدد مرات تسجيلات الدخول التي ترغب في إضافتها. والآن ستنشئ ملف إعدادات لنشر Eclipse Theia، وستخزنها في ملف يسمى eclipse-theia-compose.yaml، أنشئه باستخدام محرر النصوص الخاص بك: nano eclipse-theia-compose.yaml أضف الأسطر التاليّة في ملف ‎~/eclipse-theia/eclipse-theia-compose.yaml: version: '2.2' services: eclipse-theia: restart: always image: theiaide/theia:next init: true environment: - VIRTUAL_HOST=theia.your_domain - LETSENCRYPT_HOST=theia.your_domain عرّفت في هذه الإعدادات خدمة واحدة تسمى eclipse-theia مع خيار restart قيمته always وصورة حاوية theiaide/theia:next ولقد حدّدت init كـ true لإعلام Docker باستخدام init كمدير العمليّة الرئيسي عند تشغيل Eclipse Theia داخل الحاويّة. وبعد ذلك، ستحدّد متغيري بيئة في قسم environment وهما VIRTUAL_HOST و LETSENCRYPT_HOST فالأول سيمرر إلى nginx-proxy وسيخبره على أي نطاق يجب كشف الحاوية، وأما الآخر فسيستخدم من قبل Let's Encrypt لتحديد أي نطاق لطلب شهادات TLS، وفي العادة سيكونان نفسهما إلا لو وضع wildcard كقيمة لـ VIRTUAL_HOST. تذكر استبدال theia.your_domain مع اسم النطاق المطلوب، ومن ثم أغلق الملف بعد حفظه. والآن، انشر Eclipse Theia عن طريق كتابة الأمر: docker-compose -f eclipse-theia-compose.yaml up -d ستكون المخرجات كالتالي: ... Pulling eclipse-theia (theiaide/theia:next)... next: Pulling from theiaide/theia 63bc94deeb28: Pull complete 100db3e2539d: Pull complete ... Digest: sha256:c36dff04e250f1ac52d13f6d6e15ab3e9b8cad9ad68aba0208312e0788ecb109 Status: Downloaded newer image for theiaide/theia:next Creating eclipse-theia_eclipse-theia_1 ... done بعد ذلك في متصفحك، انتقل إلى النطاق الذي تستخدمه لـ Eclipse Theia، سيظهر لك المتصفح واجهة تسجيل الدخول، وبعد توفير البيانات الصحيحة، ستدخل إلى Eclipse Theia وسترى الواجهة الرسوميّة. يدل القفل في شريط العنوان إلى أن الإتصال مؤمن، وإذا لم ترى هذا بشكل فوري، انتظر بضعة دقائق لإصدار شهادات TLS وأعد تحميل الصفحة. والآن، يمكنك الوصول إلى IDE السحابي، ويمكنك البدء باستخدام المحرّر في الخطوة القادمة. الخطوة الثالثة - استخدام واجهة Eclipse Theia ستكتشف في هذا القسم بعض من مميزات واجهة Ecipse Theia. على الجانب الأيسر من IDE، ستجد صف عمودي من أربعة أيقونات لفتح المميزات الشائعة في اللوحة الجانبيّة. يمكنك تخصيص هذا الشريط أي يمكنك تحريك هذه المناظر (Views) لتغيير ترتيبهم أو حذفهم من الشريط. المنظر الأول بشكل افتراضي يفتح لوحة الاكتشاف (Explorer panel) والذي يوفر تصفح شجري لهيكل المشروع، يمكنك إدارة مجلداتك وملفاتك هنا من حيث إنشاء وحذف ونقل وإعادة تسميتهم حسب المطلوب. بعد إنشاء ملف جديد عن طريق قائمة File، سيُفتح ملف فارغ في علامة تبويب جديدة، وبمجرد حفظه، يمكنك رؤية اسم الملف في لوحة الاكتشاف الجانبيّة، ولإنشاء المجلدات، اضغط بالزر الأيمن على شريط Explorer وانقر على New Folder، ويمكنك توسعة المجلد عن طريق الضغط على اسمه وسحب وافلات الملفات والمجلدات إلى الأجزاء العليا من التسلسل الهرمي لتحريكهم إلى المكان الجديد. يوفر المنظر (view) التالي الوصول إلى وظائف البحث والاستبدال، ويوفّر المنظر الثالث لأنظمة التحكم بالمصدر التي قد تستخدمها، مثل Git. أما بالنسبة إلى المنظر الأخير فهو لخيار التنقيح، والذي يوفر الإجراءات الشائعة في اللوحة، ويمكنك حفظ إعدادات التنقيح في ملف launch.json. الجزء الأوسط من الواجهة هو محرّرك، والذي يمكنك فصله بعلامات التبويب لتعديل الشيفرة البرمجيّة، يمكنك تغيير منظر التعديل إلى وضع الشبكة (grid) أو إلى ملفات كل واحدة بجانب الأخرى، ومثل جميع IDE الحديثة، يدعم Eclipse Theia تسليط الضوء على الصياغة لشيفرتك البرمجيّة. يمكنك الوصول إلى الطرفيّة عن طريق ‎CTRL+SHIFT+`‎ أو عن طريق النقر على Terminal في القائمة العلويّة، وتحديد New Terminal، ستفتح الطرفية في لوحة السفليّة وستعمل في المجلد المشروع، والذي سيحتوي على جميع الملفات والمجلدات الموجودة في لوحة Explorer الجانبيّة. والآن لقد تعرّفت على واجهة Eclipse Theia مع أهم المميزات شائعة الاستخدام. الختام الآن، لديك Eclipse Theia مثبت على خادم أوبنتو 18.04 باستخدام Docker Compose وnginx-proxy، ولقد أمنته باستخدام شهادة TLS من Let’s Encrypt مجانيّة وأعددت المثيل لطلب بيانات تسجيل الدخول من المستخدم، يمكنك العمل على شيفرتك المصدريّة والوثائق بشكل فردي أو بالتعاون مع فريقك، ويمكنك تجربة بناء نسختك الخاصة من Eclipse Theia إذا احتجت إلى وظائف إضافيّة، للمزيد من المعلومات حول كيفيّة فعل ذلك، زر توثيق Theia. ترجمة -وبتصرف- للمقال How To Set Up the Eclipse Theia Cloud IDE Platform on Ubuntu 18.04 لصاحبه Savic
  3. يزداد كل يوم عدد المشاريع البرمجيّة المبنيّة بواسطة فرق تعمل من مناطق جغرافيّة مختلفة، وعلى الرغم من مميزات هذه الطريقة، إلا أن هذه الفرق تحتاج في بعض الحالات لربط حواسيبها مع بعضها البعض عبر الإنترنت والتعامل معها على أنها في نفس المكان، فعلى سبيل المثال، قد تستخدم أنظمة الموزّعة مثل Kubernetes أو تبني تطبيقًا معقدًا ذا خدمات متعدّدة وفي بعض الأحيان، سترّفع من الإنتاجية لو كان يمكنك التعامل مع الأجهزة على أن كل واحدة منها بجانب الأخرى لكي لا تتعرّض لخطر تعريض الخدمات غير جاهزة إلى الأنترنت، ويمكنك تحقيق هذا النموذج عن طريق شبكات المعرّفة بالبرمجيات Software-Defined Networking (أي SDN) التي تعتبر تكنولوجيا جديدة تسمح بإنشاء شبكة حيويّة مبنيّة بشكل كامل على البرمجيات. سنستخدم في هذا الدرس ZeroTier One وهو تطبيق مفتوح المصدر يستخدم آخر تكنولوجيات SDN للسماح للمستخدمين بإنشاء شبكات محميّة وقابلة للإدارة والتعامل مع الأجهزة المتصلة على أنها في نفس المكان الفيزيائي. يوفّر لك تطبيق ZeroTier طرفيّة (console) للويب لإدارة الشبكة وتطبيقات الأطراف (endpoint) للعملاء، فهي تكنولوجيات مشفّرة ند للند، أي أنها بخلاف حلول VPN التقليديّة، فلا تحتاج عند الإتصالات المرور إلى خادم مركزي أو موجّه، فالرسائل ترسل مباشرةً من جهاز إلى آخر ونتيجة لذلك فهي فعالة جدا وتضمن الحد الأدنى من وقت الاستجابة. من المميزات الأخرى لهذا التطبيق هو سهولة عملية النشر والإعداد ووضوح عملية الصيانة، ويسمح بالتسجيل المركزي وإدارة العقد المأذون لها عن طريق طرفيّة الويب. في هذا الدرس، ستربط عميل وخادم معًا في شبكة نقطة-إلى-نقطة (point-to-point) بسيطة، وبما أن الشبكات المعرّفة بالبرمجيات لا تستخدم تصميم العميل/الخادم التقليدي، فلا يوجد خادم VPN مركزي للتثبيت والإعداد، فيبسّط هذا نشر الأداة وإضافة أي عقد إضافيّة. وبمجرّد تأسيس الاتصال، ستحصل على فرصة استخدام قدرات VPN ZeroTier عن طريق استخدام بعض وظائف لينكس الذكيّة للسماح لحركة الحزم بمغادرة شبكة ZeroTier من خادمك وإرشاد العميل لإرسال حركة حزمه إلى ذلك الاتجاه. المتطلبات الأساسيّة قبل البدء، سنحتاج إلى هذه المتطلبات: خادم أبونتو 18.04، وستحتاج على هذا الخادم، مستخدم عادي مع صلاحيات sudo والتي يمكنك إعدادها عن طريق درس إعداد خادم أبنتو 18.04. حساب على ZeroTier One والذي يمكنك إعداده عن طريق الذهاب إلى My ZeroTier، النسخة المجانيّة من هذه الخدمة تفي بالغرض في هذا الدرس. حاسوب محلي للانضمام إلى SDN كعميل. في الأمثلة في هذا الدرس، ستجد أن كل من الخادم والحاسوب المحلي يعملان على نظام لينكس أوبنتو لكن يمكنك استخدام أي نظام تشغيل موجود على صفحة ZeroTier. الآن، أنت مستعد لإعداد شبكة معرّفة بالبرمجيات للخادم والجهاز المحلي. الخطوة الأولى - إنشاء شبكة معرفة بالبرمجيات باستخدام ZeroTier One توفّر منصة ZeroTier النقطة المركزيّة للتحكم بالشبكة المعرّفة بالبرمجيات الخاصة بك، ومن هناك يمكنك تخويل ومنع العملاء ويمكنك اختيار مخطّط العنونة وإنشاء معرّف الشبكة الذي ستستخدمه في توجيه عملائك في مرحلة الإعداد. سجّل دخولك على حساب ZeroTier، ثم أضغط على Networks في أعلى الشاشة، ومن ثم على Create. سيظهر لك اسم شبكة مولّد بشكل آلي، اضغط عليه لرؤية شاشة إعدادات الشبكة، تذكّر معّرف الشبكة Network ID الملوّن بالأصفر لأننا سنحتاجه في وقت لاحق. إذا أردت، يمكنك تغيير اسم الشبكة إلى اسم آخر أو إضافة تعليق، وسيُحفظ أي تغيير ويطبّق بشكل آلي. بعد ذلك اختر أي نطاق عناوين IPv4 سيتعامل معه SDN، على الجانب الأيمن من الشاشة في المساحة المسماة IPv4 Auto-Assign، اختر نطاق عناوين التي ستستخدمُه العقد الخاصة بك، بالنسبة لهذا الدرس، يمكنك اختيار أي مجال، ولكنك تأكد من اختيار Auto-Assign from Range. تأكد من بقاء Access Control في الجانب الأيسر على قيمة Certificate ‏(Private Network)، يضمن هذا أنه يمكن للأجهزة المخوّلة فقط الاتصال بشبكتك، وليس أي شخص لديه معرّف الشبكة الخاص بك. ستبدو الإعدادات كالتالي عند الإنتهاء منها: في هذه المرحلة، أنهيّت أساس شبكة معرّفة بالبرمجيات، في الخطوة القادمة، سنثبّت برنامج ZeroTier على خادمك وأجهزة العميل للسماح لهم بالاتصال بـ SDN الخاص بك. الخطوة الثانية - تثبيت عميل ZeroTier One على خادمك والحاسوب المحلي بما أن ZeroTier One يعتبر برنامجًا جديدًا، فهو غير موجود في مستودعات برامج أوبنتو، ولهذا السبب، يوفّر ZeroTier سكربت التثبيت والذي سيُستخدم لتثبيت البرنامج و يحتوي على سكربت توقيع-GPG، أي سيتأكد من أن الشيفرة البرمجيّة التي ستثبتها منشورة بواسطة ZeroTier. curl -s 'https://pgp.mit.edu/pks/lookup?op=get&search=0x1657198823E52A61' | gpg --import && if z=$(curl -s 'https://install.zerotier.com/' | gpg); then echo "$z" | sudo bash; fi يملك هذا السكربت أربعة أجزاء أساسية وهذا تفسير كل جزء منها: curl -s 'https://pgp.mit.edu/pks/lookup?op=get&search=0x1657198823E52A61' سيستدعي هذا الجزء مفتاح ZeroTier العام من `MIT. gpg --import يضيف هذا القسم مفتاح العام لـ ZeroTier إلى سلسلة المفاتيح المحلية للتخويلات للوثوق في الحزم التي ترغب في تثبيتها. الجزء التالي من الأمر سيُنفّذ فقط إذا انتهى استدعاء GPG بنجاح. if z=$(curl -s 'https://install.zerotier.com/' | gpg); then echo "$z" يمكنك ترجمة هذا القسم إلى : إذا كان سكربت التثبيت الموقّع بالتشفير منزّل من ZeroTier.com ومّر من GPG ولن يعترض عليه على انه غير موقّع من ZeroTier، اعرض هذه المعلومة على الشاشة. sudo bash; fi يأخذ هذا القسم السكربت المتحقق منه في ويٌنفّذه قبل الانتهاء. تحذير: لا تنزّل شيء من الانترنت وتربطه ببرنامج آخر إلا لو تأكدت منه من مصدر موثوق. يمكنك فحص الشيفرة المصدرية لبرنامج ZeroTier على صفحة GitHub الخاصة بالمشروع إذا رغبت في ذلك. استخدم طرفيّة SSH للاتصال بخادمك المنشئ حديثّا وشغّل الأمر السابق كمستخدم عادي تأكد أنك لا تشغّل هذا الأمر بصلاحيات الجذر، لأن السكربت سيطلب بشكل تلقائي كلمة المرور الخاصة بك لرفع مستوى الصلاحيات، وتذكر إبقاء طرفيّة ZeroTier مفتوح في متصفحك حتى تتمكّن من التعامل معه عند الضرورة. بمجرّد أن ينتهي السكربت من العمل، ستجد سطرين مشابهين للسطرين التاليين، سجّل عنوان ZeroTier (بدون الأقواس المعقوفة) واسم النظام الذي ولّد هذا العنوان لأنك ستحتاجهم فيما بعد: *** Waiting for identity generation... *** Success! You are ZeroTier address [ 916af8664d ]. أعد هذه الخطوات على حاسوبك المحلي إذا كنت تستخدم نظام أوبنتو أو اتبع الخطوات الموجودة على موقع ZeroTier إذا كنت تستخدم نظامًا آخرًا. ومرّة أخرى احفظ عنوان ZeroTier والجهاز الذي يولّد هذا العنوان، لأنك ستحتاج إلى هذه المعلومات في الخطوة التالية من الدرس عندما تضم الخادم والعميل إلى الشبكة. الخطوة الثالثة - الانضمام إلى شبكة ZeroTier الخاصة بك بعد تشغيل برنامج ZeroTier على كل من الخادم والعميل، أنت الآن مستعد لتوصيلهم إلى الشبكة التي أنشأتها في طرفيّة ويب ZeroTier. استخدم الأمر التالي لتوجيه العميل الخاص بك لطلب الوصول إلى شبكة ZeroTier عن طريق المنصة الخاصة بهم، سيُرفض الطلب الأول للعميل وسيبقى معلّقًا، لكننا سنصلح ذلك بعد لحظات. تأكد من استبدال NetworkID بمعرّف الشبكة الذي سجلناه سابقًا في نافذة إعداد الشبكة. sudo zerotier-cli join NetworkID ستكون النتيجة كالتالي: 200 join OK ستحصل على رسالة 200 join OK لتأكيد أن خدمة ZeroTier قد اشتغلت على خادمك، وإذا لم تحصل على هذه الرسالة، تأكد من معرّف الشبكة الذي أدخلته. بما أنك لم تنشئ شبكة عامة يمكن لأي شخص في العالم الإنضمام إليها، ستحتاج الآن إلى تخويل عملائك، اذهب إلى طرفيّة ويب ZeroTier وستجد في الأسفل قسم Members، ستجد المدخلات مع علامة Online، بنفس العناوين التي أدخلتها سابقًا. في العمود الأول Auth?‎، ضع إشارة على المربع لتخويلهم للانضمام إلى الشبكة، سيخصص متحكم ZeroTier عنوان IP للخادم وللعميل من النطاق الذي اخترته سابقا لاستخدامهم في المرة القادمة عند استدعاء SDN. يحتاج تخصيص عناوين IP بعض الوقت، في أثناء انتظار انتهاء العملية، يمكنك توفير Short Name و Description للعقد في قسم Members. وبهذا، ربطت النظامين إلى شبكة المعرّف بالبرمجيات الخاصة بك. حتى الآن تعرفنا على بعض أساسيات لوحة تحكم ZeroTier، ولقد استخدمنا واجهة سطر الأوامر لتنزيل وتثبيت ZeroTier، ومن ثم ربط كل من الخادم والعميل لتلك الشبكة، وبعد ذلك، ستتأكد من تطبيق كل شيء بشكل جيّد عن طريق أداء اختبار اتصال. الخطوة الرابعة - التحقق من الاتصال في هذه المرحلة، من المهم التحقق من أن كِلا الجهازين يمكنهما التواصل مع بعضهم البعض، فهنالك امكانية أنه لا يمكن التواصل فيما بينهم حتى لو ادعوا أنهم انضموا إلى الشبكة. ومن خلال التحقق من الاتصال الآن، لا تحتاج إلى القلق بشأن مشكلات الترابط الأساسيّة التي قد تسبب مشكلة في وقت لاحق. من الطرق السهلة لإيجاد عنوان IP الخاص بـ ZeroTier لكل جهاز هو النظر إلى قسم Members في طرفيّة ويب ZeroTier، ربما ستحتاج إلى تحديث الصفحة بعد التخويل للخادم والعميل قبل ظهور عناوين IP الخاصة بهم، وبدلًا من ذلك، توجد طريقة أخرى لفعل هذا وذلك عن طريق استخدام سطر أوامر لينكس لإيجاد هذه العناوين، استخدم الأمر التالي على كِلا الجهازين، عنوان IP الأول الذي يظهر في القائمة هو الذي سنستخدمه، في المثال أدناه، العنوان هو 203.0.113.0. ip addr sh zt0 | grep 'inet' ستكون المخرجات كالتالي: inet 203.0.113.0/24 brd 203.0.255.255 scope global zt0 inet6 fc63:b4a9:3507:6649:9d52::1/40 scope global inet6 fe80::28e4:7eff:fe38:8318/64 scope link لتجربة الاتصال بين الأجهزة، استخدم الأمر ping من أحد الأجهزة متبوع باسم عنوان IP الآخر، فعلى سبيل المثال، على جهاز العميل: ping your_server_ip وعلى الخادم: ping your_client_ip إذا عادت نتيجة من الجهاز الآخر (كما هو موضّح في المخرجات أسفله)، فإن كلا العقدين يتواصلان عبر SDN بنجاح. PING 203.0.113.0 (203.0.113.0) 56(84) bytes of data. 64 bytes from 203.0.113.0: icmp_seq=1 ttl=64 time=0.054 ms 64 bytes from 203.0.113.0: icmp_seq=2 ttl=64 time=0.046 ms 64 bytes from 203.0.113.0: icmp_seq=3 ttl=64 time=0.043 ms يمكنك إضافة أي عدد من الأجهزة إلى هذه الإعدادات عن طريق إعادة تثبيت ZeroTier وضمهم كما وضحنا في الأعلى. تذكر أن هذه الأجهزة لا تحتاج إلى أن تكون قريبة من بعضها البعض بأي طريقة. والآن، بعد أن تأكدت من أن الخادم والعميل يمكنهم التواصل مع بعضهم البعض، واصل القراءة لتتعلم كيف يمكنك ضبط الشبكة لتوفير بوابة خروج (exit gateway) وبناء VPN خاص بك. الخطوة الخامسة - تفعيل قدرات VPN الخاصة بـ ZeroTier كما ذكرنا في المقدمة، يمكنك استخدام ZeroTier كأداة VPN، إذا كنت لا تخطط لاستخدام ZeroTier كحل VPN، فلا تحتاج إلى اتباع هذه الخطوة ويمكنك القفز مباشرةً إلى الخطوة السادسة. إن استخدام VPN يخفي مصدر اتصالاتك مع المواقع عبر الانترنت، ويسمح لك بتجاوز القيود التي قد تكون موجودة في الشبكة التي تستخدمها، فأنت بالنسبة للإنترنت، تتصفحه عن طريق عنوان IP العام للخادم. ولكي تستخدم ZeroTier كأداة VPN، ستحتاج إلى القيام بمزيد من التغييرات لخادمك وإعدادات العميل. تفعيل ترجمة عنوان الشبكة وإعادة توجيه عنوان IP ترجمة عنوان الشبكة (Network Address Translation) والذي يعرف بـ "NAT"، هي طريقة تمكّن الموجّه (router) من قبول الحزم في واجهة واحدة موسومة بعنوان IP المرسل ومن ثم تبديل ذلك العنوان بعنوان الموجّه. يحفظ سجل هذا التبادل في ذاكرة الموجّه بحيث عند عودة الحزم في الاتجاه المعاكس، يمكن للموجّه ترجمة عنوان IP مرّة أخرى إلى عنوانه الأصلي. يستخدم NAT في العادة للسماح لعدة حواسيب للعمل باستخدام عنوان IP واحد ظاهر للعموم، والذي هو مفيد بالنسبة لخدمة VPN، ومثال على NAT، الموجه المنزلي الذي يقدمه لك مزوّد خدمة الإنترنت لتتصل جميع الأجهزة في منزلك بالإنترنت. فيشترك حاسوبك وهاتفك وأجهزتك اللوحية في نفس عنوان IP لشبكة الأنترنت، لأن الموجّه يستخدم NAT. عن رغم من أن الموجه هو من يقوم بـ NAT، فيمكن للخادم فعل ذلك أيضًا، وعن طريق هذه الخطوة، ستستفيد من هذه الوظيفة في خادم ZeroTier لتفعيل قدرات VPN. إن عملية إعادة توجيه عنوان IP ‏(IP forwarding) هي وظيفة يقوم بها الموجّه أو الخادم لتوجيه حركة الحزم من واجهة إلى أخرى إذا كانت عناوين IP في مناطق مختلفة. إذا كان الموجّه متّصل بشبكتين، فيسمح إعادة توجيه عنوان IP بتوجيه الحزم فيما بينهم. يبدو هذا سهلًا، لكن قد تواجه صعوبات في تطبيقه، أما في هذا الدرس، فمجرّد تعديل بضعة ملفات إعداد. بتفعيل إعادة توجيه IP، ستصل حركة الحزم للـ VPN من عميلك في شبكة ZeroTier إلى واجهة ZeroTier للخادم، وبدون هذه الإعدادات، ستحذف نواة لينكس (افتراضيًا) أي حزم تصل لواجهة ليست لها، وهذا هو سلوكها الافتراضي، لأنه في العادة أي حزم تصل إلى واجهة لديها عنوان وصول شبكة أخرى قد تكون بسبب خطأ من الموجه في الشبكة. اعتبر إعادة توجيه عنوان IP على أنه إعلام نواة لينكس أنه يمكن إعادة توجيه الحزم بين الواجهات، فالوضع الافتراضي هو 0 أي مغلق، والذي ستحوله إلى 1 أي مفعّل. شغّل الأمر التالي لرؤية الإعدادات الحالية: sudo sysctl net.ipv4.ip_forward ستبدو المخرجات كالتالي: net.ipv4.ip_forward = 0 لتفعيل إعادة توجيه عنوان IP، عدّل على ملف ‎/etc/sysctl.conf في خادمك وأضف السطر المطلوب، يسمح هذا الملف للمدراء بتجاوز إعدادات النواة الافتراضية وسيظّل يعمل دائما حتى بعد إعادة التشغيل لذلك لا تقلق بشأن إعداده مرّة أخرى. استخدم nano أو محرر النصوص المفضّل لديك لإضافة السطر التالي إلى نهاية الملف: sudo nano /etc/sysctl.conf ثم أضف السطر التالي: . . . net.ipv4.ip_forward = 1 اغلق الملف بعد حفظه ثم شغّل الأمر التالي لإعلام النواة بالتغييرات. sudo sysctl -p سيتبني الخادم أي تغييرات في الإعدادات من الملف وسيطبقها فورا دون الحاجة إلى إعادة التشغيل، شغل نفس الأمر الذي كتبناه سابقا وستجد أن إعادة توجيه IP مفعّل. sudo sysctl net.ipv4.ip_forward ستكون المخرجات كالتالي: net.ipv4.ip_forward = 1 والآن، بعد تفعيل إعادة توجيه عناوين IP، سنضع بعض القواعد لإعادة توجيه بسيطة للخادم، بما أن نواة لينكس تملك القدرة على توجيه الشبكة بداخلها، فكل ما عليك فعله هو إضافة بعض القواعد لاخبار الجدار الناري الداخلي والموجّه أن حركة الحزم الجديدة مقبولة وأين سيرسلها. لإضافة هذه القواعد من سطر الأوامر، ستحتاج أولًا إلى معرفة أسماء التي أعطاها أوبنتو لكل من واجهة ZeroTier وواجهة إثرنت Ethernet للإنترنت العادي، سيكونان في العادة zt0 و eth0 لكن ليس دائمًا. لإيجاد أسماء هذه الواجهات، استخدم الأمر ip link show، هذه الأداة هي جزء من iproute2 وهي مجموعة من أدوات مساحة المستخدم والتي تأتي مثبتة في أبنتو بشكل افتراضي: ip link show في مخرجات هذا الأمر، ستجد أسماء الواجهة بجانب الأرقام التي تعرّف الواجهة في القائمة، إذا وجدّت أسماء مختلفة عن الموجودة في المثال، فاستخدمها في بقيّة الدرس: 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000 link/ether 72:2d:7e:6f:5e:08 brd ff:ff:ff:ff:ff:ff 3: zt0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 2800 qdisc pfifo_fast state UNKNOWN mode DEFAULT group default qlen 1000 link/ether be:82:8f:f3:b4:cd brd ff:ff:ff:ff:ff:ff وبعد ذلك استخدم iptables لتفعيل ترجمة عناوين الشبكة (Network-Address-Translation) وعمليّة تنكر IP ‏(IP masquerading): sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE اسمح بتوجيه حركة الحزم وراقب الاتصالات النشطة: sudo iptables -A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT بعد ذلك، اسمح بتوجيه حركة الحزم من zt0 إلى eth0، والقاعدة المعاكسة لهذه غير مطلوبة بما أنك ستفترض أن العميل يتصل دائمًا من هذا الخادم، وليس من طريق آخر: sudo iptables -A FORWARD -i zt0 -o eth0 -j ACCEPT من المهم تذكّر أن قواعد iptables التي وضعتها لهذا الخادم لا تبقى عند إعادة التشغيل، ستحتاج إلى حفظ هذه القواعد لإعادتها في حالة إعادة تشغيل الخادم، شغّل الأوامر في الأسفل وسترى كيف يمكنك بشكل مختصر حفظ قواعد IPv4 الحاليّة (IPv6 غير مطلوبة في الوقت الحالي): sudo apt-get install iptables-persistent sudo netfilter-persistent save بعد تنفيذ الأمر sudo netfilter-persistent save من الأفضل إعادة تشغيل الخادم للتأكد من أن القواعد قد حفظت بشكل صحيح، وأسهل طريقة للتأكد من ذلك هو عن طريق تشغيل sudo iptables-save والذي سيعرض الإعداد الموجود حاليًا في ذاكرة إلى الطرفية. إذا رأيت قواعد مشابهة للقواعد في الأسفل بغض النظر عن التنكر، إعادة التوجيه IP وواجهة zt0، فإنها حفظت بشكل صحيح. sudo iptables-save المخرجات: # Generated by iptables-save v1.6.0 on Tue Apr 17 21:43:08 2018 . . . -A POSTROUTING -o eth0 -j MASQUERADE COMMIT . . . -A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT -A FORWARD -i zt0 -o eth0 -j ACCEPT COMMIT . . . بعد تطبيق هذه القواعد على الخادم، يمكنك الآن نقل الحزم بين شبكة ZeroTier والانترنت العام، ومع ذلك، لن يعمل VPN إلا لو أُعلمت شبكة ZeroTier نفسها أن الخادم جاهز لاستخدامه كبوابة خروج (gateway). تفعيل خادمك لإدارة التوجيه العمومي (Global Route) من أجل أن يتمكن خادمك من معالجة حركة الحزم من أي عميل، يجب أن تتأكد من معرفة العملاء الآخرين في شبكة ZeroTier كيف يرسلون حركة الحزم له، وذلك عن طريق إعداد توجيه عمومي (Global Route) في طرفيّة ZeroTier، يعرّف الأشخاص المختصين في شبكات الحاسوب بالتوجيه الافتراضي (Default Route)، وتعني أين سيرسل كل عميل حركة الحزم الافتراضية، على سبيل المثال، منع توجيه حركة الحزم لمناطق أخرى محددّة. اذهب إلى أعلى يمين صفحة شبكات ZeroTier وأضف موجّه جديد بمعاملات التالية، يمكنك إيجاد عنوان IP ZeroTier لخادمك في قسم Members من صفحة إعدادات شبكة ZeroTier، وفي حقل network/bits، أضف 0.0.0.0/0 وفي حقل (LAN)، أدخل عنوان IP خادم ZeroTier. بعد اضافة هذه التفاصيل، اضغط على رمز "+" وسترى ظهور قاعدة جديدة أسفل القاعدة الموجودة، وسترى كرة برتقالية للإعلام بأنه توجيه عمومي. لم يتبقى سوى إعداد العملاء قبل أن يعمل VPN. إعداد عملاء لينكس ملاحظة: الأوامر الموجودة في هذا القسم تطبّق فقط على عملاء لينكس، بالنسبة إلى تعليمات إعداد عملاء ويندوز وmacOS فستجدها في القسم القادم. إذا كان العميل يعمل بنظام لينكس، فستحتاج إلى القيام بتغييرات يدوية في ملف ‎/etc/sysctl.conf . هذه الإعدادات مطلوبة لتغيير معلومات النواة حول مسار العودة المقبول من حركة حزم العميل، وبسبب الطريقة التي أُعدّ به ZeroTier VPN، فحركة الحزم القادمة من خادمك إلى عميلك قد تظهر أنها تأتي من عنوان شبكة مختلف عن الذي أرسلت إليه، وبشكل افتراضي، سترى نواة لينكس أنها غير صالحة وستحذفها، لذلك من الضروري تغيير هذا السلوك. افتح ملف ‎/etc/sysctl.conf على جهاز العميل: sudo nano /etc/sysctl.conf وأضف السطر التالي: . . . net.ipv4.conf.all.rp_filter=2 أغلق الملف بعد حفظه وشغّل الأمر التالي لتطبيق التغييرات: sudo sysctl -p بعد ذلك، اخبر برنامج عميل ZeroTier أن الشبكة مسموح لها بحمل حركة الحزم الافتراضيّة، أي أنه سيعدّل على توجيه العميل، ويجب تفعيلها بشكل يدوي لأن الأمر حساس، سيعرض هذا الأمر هيكل الإعدادات، تأكد من أن allowDefault=1 في الأعلى: sudo zerotier-cli set NetworkID allowDefault=1 إذا أردت في أي وقت ايقاف استخدام ZeroTier كـ VPN مع إبقاء حركة الحزم داخله، أعد قيمة allowDefault إلى 0: sudo zerotier-cli set NetworkID allowDefault=0 في كل مرة تعيد تشغيل جهاز العميل، ستعود قيمة allowDefault=1 إلى 0 فتذكّر إعادة تنفيذها من أجل تفعيل وظيفة VPN. تعمل خدمة ZeroTier بشكل افتراضي عند التشغيل لكل من عميل لينكس والخادم، وإذا لم ترغب بهذا، فيمكنك إيقاف تشغيلها عند اقلاع الحاسوب عن طريق الأمر التالي: sudo systemctl disable zerotier-one إذا أردت استخدام نظام تشغيل آخر على شبكة ZeroTier فأقرأ القسم التالي، وخلاف لذلك انتقل إلى القسم الذي بعده. إعداد عملاء لا يعملون بنظام لينكس لا يقتصر عمل برنامج عميل ZeroTier على نظام لينكس فقط، فيمكن دعم حتى الهواتف الذكية، فالبرنامج متوفّر لأنظمة ويندوز وmacOS وأندرويد وiOS و حتى أنظمة التشغيل المتخصصة كنظام QNAP و Synology و WesternDigital NAS. لضم عملاء يعملون بأنظمة macOS وويندوز إلى الشبكة، شغّل أداة ZeroTier (والتي ثبتها في الخطوة 1) ومن ثم أدخل NetworkID في الحقل قبل أن تضغط على Join. تذكر بأن تعود إلى طرفيّة ZeroTier لاختيار زر Allow لتخويل النظام الجديد إلى شبكتك. تأكد من وضع اشارة على المربع المسمى Route all traffic through ZeroTier، وإذا لم تفعل ذلك، فالعملاء سيرتبطون بشبكة ZeroTier لكن لن يتمكنوا من ارسال حركة حزم الإنترنت عبرها. استخدم أداة للتأكد من عنوان IP مثل ICanHazIP للتأكد من أن الحزم تظهر إلى الإنترنت من خلال عنوان IP الخادم، وللتأكد من ذلك، أضف عنوان URL التالي إلى شريط عنوان متصفحك، وسيظهر لك هذا الموقع عنوان IP الذي يراه الخادم (وبقيّة الانترنت) للوصول إلى الموقع: http://icanhazip.com. وبانتهاء هذه الخطوات، يمكنك بدء استخدام VPN الخاص بك كما تريد، القسم الاختياري التالي سيغطي ميّزة قواعد التدفق (flow rules) الموجودة في ZeroTier SDN، لكنها ليست مطلوبة لعمل وظيفة VPN. الخطوة السادسة - إدارة التدفق (اختياري) واحدة من فوائد الشبكة المعرّفة بالبرمجيات هي التحكم المركزي، فواجهة مستخدم الويب هي المتحكم المركزي لـ ZeroTier والتي تترأس كامل خدمة ZeroTier SDN، ومن هذه الواجهة، يمكن كتابة قواعد تعرف باسم قواعد التدفّق والتي تحدّد ما يمكن لحركة الحزم في الشبكة فعله أو لا، فعلى سبيل المثال، يمكنك حظر منافذ معيّنة في الشبكة، وتقييد الأجهزة التي يمكنها التحدث لبعضها وحتى إعادة توجيه حركة الحزم. هذه القدرة مهمة للغاية ويسري مفعولها بشكل فوري تقريبًا، لأن أي تغييرات على جدول التدفّق ترسل إلى أعضاء الشبكة ويسري مفعولها بعد لحظات. لتعديل قواعد التدفّق، إذهب إلى واجهة مستخدم ويب ZeroTier، واضغط على تبويب Networking، وانزل قليلا إلى الأسفل حتى ترى مربع يسمى Flow Rules (والذي سيتوسع)، ويفتح هذا حقل نصي حيث يمكنك إضافة القواعد التي ترغب بها. ستجد كتيّب كامل مع طرفيّة ZeroTier في المربع الذي أسفل مربع ادخال Flow Rules ويسمى Rules Engine Help. وإليك بعض الأمثلة لقواعد ستساعدك على اكتشاف هذه الوظيفة. لحظر أي حركة حزم ملزمة لخادم DNS جوجل 8.8.8.8، أضف هذه القاعدة: drop ipdest 8.8.8.8/32 ; لإعادة توجيه أي حركة حزم ملزمة لخادم DNS جوجل العامل إلى إحدى عقد ZeroTier، أضف القاعدة التالية، يمكن أن يكون هذا بمثابة اختبارًا ممتازًا لتجاوز عمليات بحث (lookups) DNS: redirect NetworkID ipdest 8.8.8.8/32 ; إذا كان لشبكتك متطلبات حماية خاصة، يمكنك إزالة أي نشاط على منافذ FTP و Telnet و HTTP غير المشفّر عن طريق اضافة هذه القاعدة: drop dport 80,23,21,20 ; عندما تنتهي من إضافة قواعد التدفّق، اضغط على زر Save Changes وسيسجّل ZeroTier التغييرات. خاتمة تعلمّت في هذا الدرس بعض من أساسيات شبكات المعرّفة بالبرمجيات، ووفر لك ZeroTier بعض اللمحات حول فائدة هذه التكنولوجيا وعلى الرغم من تثبيت VPN قد يتعارض مع أدوات أخرى قد استخدمتها في الماضي، لكن سيكون سهولة إضافة عملاء جدد سببًا مقنعًا لاستخدام التكنولوجيا في مكان آخر. لتلخيص الأمر، لقد تعلمت كيفية استخدام ZeroTier كموفّر SDN، بالإضافة إلى إعداد وربط العقد إلى الشبكة، ولقد علمك عنصر VPN كيف يعمل التوجيه وكيف تعمل الشبكة، وسيسمح لك هذا الدرس باستخدام تكنولوجيا التحكم بالتدفّق. والآن بعد أن أضفنا شبكة نقطة-إلى-نقطة، يمكنك جمعها مع تكنولوجيا أخرى مثل مشاركة الملفات، وإذا كان لديك NAS أو خادم ملفات في البيت فيمكنك ربطه بـ ZeroTier واستخدامه. إذا أردت مشاركته مع أصدقائك، فيمكنك أن تفسّر لهم كيف ينضمون إلى شبكة ZeroTier الخاصة بك. ترجمة -وبتصرف- للمقال Getting Started with Software-Defined Networking and Creating a VPN with ZeroTier One لصاحبه Sam Cater
  4. يعتبر دوكر Docker من أشهر التطبيقات مفتوحة المصدر لإنشاء وإدارة ونشر استنساخ التطبيقات باستخدام الحاويات، فالحاوية هي حزمة تحتوي على متطلبات التطبيق للعمل على مستوى نظام التشغيل أي أن التطبيق المنشور باستخدام Docker يعمل في بيئته الخاصة ويُتعامل مع متطلباته بشكل منفصل. أما Flask فهو إطار ويب مصغّر (micro-framework) مبني باستخدام لغة بايثون، وتعود تسميته بالإطار المصغّر لأنه لا يحتاج إلى أدوات محدّدة أو مكونات إضافيّة لكي يعمل، بالإضافة إلى أنه يتميّز بالخفّة والمرونة وبدرجة عالية من التنظيم مما يجعل المبرمجين يفضلونه على بقية الإطارات. سيسمح لك نشر تطبيق Flask باستخدام Docker باستنساخ التطبيق على مختلف الخوادم بأقل إعدادات ممكنة، لذا سنرى كيفية إنشاء تطبيق Flask و نشره باستخدام Docker بالإضافة إلى كيفية تحديث التطبيق بعد نشره. المتطلبات الأساسية لمتابعة هذا الدرس، ستحتاج إلى ما يلي: مستخدم عادي - ليس جذر - مع صلاحيات sudo معّد باستخدام هذا الدليل خادم أوبنتو 18.04 مع Docker، يمكنك إعداده عن طريق اتباع الخطوات في هذا الدرس أو عن طريق استخدام ميّزة التثبيت الخاصة بـ DigitalOcean في هذا الدرس تثبيت Nginx بإتباع الخطوة الأولى من هذا الدرس الخطوة الأولى - إعداد تطبيق Flask ستحتاج إلى إنشاء هيكل مجلدات تطبيقك، لذلك أنشئ مجلدًا في ‎/var/www وسمّهِ على سبيل المثال TestApp: sudo mkdir /var/www/TestApp ثم انتقل إلى هذا المجلد باستخدام الأمر: cd /var/www/TestApp وبعد ذلك، أنشئ المجلد الرئيسي لتطبيق Flask: sudo mkdir -p app/static app/templates تشير راية ‎-p إلى أن mkdir سينشئ المجلد مع جميع المجلدات الرئيسية غير الموجودة، وفي هذه الحالة، سينشئ mkdir مجلد الأب app حتى يتمكن من إنشاء مجلدات static و templates داخله. سيحتوي المجلد app على جميع الملفات المتعلّقة بتطبيق Flask مثل الواجهات (views) والمخططات الأوليّة (blueprints). فالواجهة هي الشيفرة البرمجيّة التي تكتبها للاستجابة إلى طلبات تطبيقك، أما المخططات الأوليّة فتنشئ مكونات التطبيق وتدعم الأنماط الشائعة داخل التطبيق أو عبر تطبيقات مختلفة. ستضع جميع الأصول مثل الصور وملفات CSS وملفات جافاسكربت في مجلد static ، وأما بالنسبة لقوالب HTML فستضعهم في مجلد templates. والآن، بعد أن أنشأنا هيكل المجلدات الأساسية، فسننشئ الملفات التي نحتاجها لتشغيل تطبيق Flask. أنشئ أولًا ملف ‎__init__.py داخل مجلد app، سيجعل هذا الملف مفسر بايثون يتعامل مع مجلد app كحزمة. أنشئ ملف ‎__init__.py باستخدام الأمر التالي: sudo nano app/__init__.py تسمح لك الحزم في بايثون بجمع الوحدات إلى مساحات أسماء منطقيّة أو تسلّسلات هرميّة لكي تتمكن من تقسيم الشيفرة البرمجيّة إلى كتل منفصلة قابلة للإدارة ذات وظائف معيّنة. بعد ذلك، ستضيف شيفرة برمجيّة إلى ‎__init__.py لإنشاء نسخة من Flask واستدعاء المنطق الموجود في ملف views.py، والذي ستنشئه بعد إنهائك لهذا الملف. أضف الشيفرة البرمجيّة التاليّة إلى الملف الجديد: from flask import Flask app = Flask(__name__) from app import views ستنشئ الآن ملف views.py في مجلد app، سيحتوي هذا الملف على أغلب منطق التطبيق. sudo nano app/views.py بعد ذلك أضف هذه الشيفرة البرمجيّة إلى ملف views.py، ستُعيد هذه الشيفرة البرمجيّة السلسلة النصيّة ‎hello world!‎ إلى زوار صفحة الويب. from app import app @app.route('/') def home(): return "hello world!" يسمى السطر ‎@app.route‎‏ فوق الدالة بالمزخرِف ويعمل على تعديل الدالة التي بعده، وفي هذه الحالة، سيخبر المزخرِف Flask أي رابط URL ستنفّذ دالة home‎‎()‎، وأما بالنسبة إلى النص hello world المُعاد من الدالة home فسيظهر للمستخدم في المتصفّح. الآن، بعد الانتهاء من ملف views.py، فنحن مستعدين لإنشاء ملف uwsgi.ini الذي سيحتوي على إعدادات uWSGI لتطبيقنا وهذا الأخير عبارة عن خيار نشر لـ Nginx والذي هو خادم لكل من البروتوكول والتطبيق، أي يخدم بروتوكولات uWSGI و FastCGI و HTTP. استخدم الأمر التالي لإنشاء هذا الملف: sudo nano uwsgi.ini بعد ذلك، أضف هذه الإعدادات إلى الملف لإعداد خادم uWSGI: [uwsgi] module = main callable = app master = true تعرّف هذه الشيفرة البرمجية الوحدة التي سيعمل منها تطبيق Flask، والتي هي في هذه الحالة ملف main.py، ولقد أشرنا إليه بـ main. وبالنسبة إلى خيار callable فهو يخبر uWSGI باستخدام نسخة من app المصدّر من التطبيق الرئيسي. ويسمح الخيار master للتطبيق أن يعمل دائمًا ولن يتوقف إلا لبعض الوقت عند إعادة تحميل التطبيق كاملًا. بعد ذلك، أنشئ ملف main.py ليكون مدخل تطبيقك، فالمدّخل يخبر uWSGI عن كيفية التعامل مع تطبيقك. sudo nano main.py والآن، أضف السطر التالي إلى الملف حيث أن هذا الأخير سيستدعي نسخة من Flask يسمى app من حزمة التطبيق التي أنشأناها سابقًا. from app import app وفي النهاية، أنشئ الملف requirements.txt لتحديد الاعتماديات التي سيثبتها مدير الحزم pip إلى نشر Docker الخاص بك: sudo nano requirements.txt أضف السطر التالي في الملف ‎/var/www/TestApp/app/requirements.txt لإضافة Flask كتبعيّة: Flask==1.0.2 يحدد هذا السطر نسخة Flask التي يجب تثبيتها، والتي هي في وقت كتابة هذا المقال، النسخة 1.0.2، ويمكنك التأكد من التحديثات على الموقع الرسمي لـ Flask. والآن لقد أنتهيت من إعداد تطبيق Flask ومستعد لإعداد Docker. الخطوة الثانية - إعداد Docker سننشئ في هذه الخطوة ملفين، Dockerfile و start.sh لإنشاء نشر Docker الخاص بك، فملف Dockerfile هو مستند نصي يحتوي على الأوامر التي تُستخدم لتجميع الصورة (image) وأما بالنسبة لملف start.sh فهو سكربت shell الذي سيبني الصورة وسينشئ الحاوية من ملف Dockerfile. أنشئ أولًا ملف Dockerfile: sudo nano Dockerfile بعد ذلك، أضف إعداداتك التي ترغب بها إلى Dockerfile، ستحدّد هذه الأوامر كيف ترغب ببناء الصورة وكيف ستضاف المتطلبات الإضافيّة. الملف ‎/var/www/TestApp/Dockerfile: FROM tiangolo/uwsgi-nginx-flask:python3.6-alpine3.7 RUN apk --update add bash nano ENV STATIC_URL /static ENV STATIC_PATH /var/www/app/static COPY ./requirements.txt /var/www/requirements.txt RUN pip install -r /var/www/requirements.txt في هذا المثال، سنبني صورة Docker (أي image) من صورة موجودة بالفعل وهي tiangolo/uwsgi-nginx-flask ويمكنك إيجادها على DockerHub وتعتبر هذه الصورة من أفضل الصور الموجودة لأنها تدعم العديد من نسخ بايثون بالإضافة إلى أنظمة التشغيل المختلفة. أول سطرين سيحددان الصورة الرئيسيّة التي ستستخدمها لتشغيل التطبيق وتثبيت معالج أوامر Bash والمحرّر النصي nano، وستثبت أيضًا عميل git للسحب والدفع إلى خدمات استضافة التحكّم بالإصدارات مثل GitHub و GitLab و Bitbucket. أما بالنسبة إلى ENV STATIC_URL /static فهو متغيّر البيئة الخاص بصورة Docker الحالية ويحدد الملف الثابت (static) الذي سيحتوي على جميع الأصول مثل الصور وملفات CSS و ملفات جافا سكربت. بالنسبة لآخر سطرين فستنسخ الملف requirements.txt إلى الحاوية ومن ثم ستثبّت التبعيات. والآن، بعد أن أنهينا ملف Dockerfile، أصبحنا مستعدين لإنشاء ملف start.sh الذي سيبني حاوية Docker، وقبل كتابة سكربت start.sh، تأكد من وجود منفذ (port) مفتوح لاستخدامه في الإعدادات، ويمكنك التأكد من ذلك عن طريق تشغيل الأمر التالي: sudo nc localhost 56733 < /dev/null; echo $? إذا كانت مخرجات الأمر السابق هي 1 فهذا المنفذ مفتوح ويمكن استخدامه، وخلافا ذلك، ستحتاج إلى اختيار منفذ آخر لاستخدامه في ملف إعدادات start.sh. بمجرّد أن تجد منفذ مفتوح للاستخدام، أنشئ سكربت start.sh: sudo nano start.sh سيبني سكربت start.sh ملف Dockerfile وينشئ الحاوية من صورة Docker، ولهذا سنضيف إلى الملف ‎‎/var/www/TestApp/start.sh‎ الإعدادات التالية: #!/bin/bash app="docker.test" docker build -t ${app} . docker run -d -p 56733:80 \ --name=${app} \ -v $PWD:/app ${app} يسمى السطر الأول بـ shebang، وهو يحدد أن هذا الملف هو ملف bash وستُنفّذ أوامره، وأما السطر الثاني فيحدّد اسم الصورة والحاوية وستُحفظ على شكل متغيّر يسمى app. أما السطر التالي فيخبر Docker ببناء الصور من ملف Dockerfile الموجود في المجلّد الحالي، وفي هذا المثال، سينشئ صورة تسمى docker.test. الأسطر الثلاثة الأخيرة تنشئ حاوية تسمى docker.test والتي تعمل على المنفذ 56733، وفي النهاية، تربط المجلد الحالي بمجلد ‎‎‎/var/www في الحاوية. يمكنك استخدام الراية ‎-d لتشغيل الحاوية في وضع العفريت (daemon mode) أو كعملية خلفيّة (background process)، ويمكنك تضمين الراية ‎-p لربط منفذ الخادم إلى منفذ معيّن في حاوية Docker، وفي هذه الحالة ستربط منفذ 59733 بمنّفذ 80 في حاوية Docker. بالنسبة إلى الراية ‎-v ‏(volume) ‏فيحدد مكان Docker لوصله في الحاوية. شغّل سكربت start.sh لإنشاء صورة Docker وبناء حاوية من الصورة: sudo bash start.sh بمجرّد الانتهاء من الأمر السابق، استخدم الأمر التالي لعرض جميع الحاويات التي تعمل: sudo docker ps سيظهر لك شيء مشابه لهذا: CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 58b05508f4dd docker.test "/entrypoint.sh /sta…" 12 seconds ago Up 3 seconds 443/tcp, 0.0.0.0:56733->80/tcp docker.test سترى أن حاوية docker.test تعمل، والآن لنزور عنوان IP في المنفذ الذي اخترناه في متصفحك: http://ip-address:56733 ستشاهد صفحة مشابهة لهذه الصفحة: في هذه الخطوة نجحنا في نشر تطبيق Flask على Docker، سنستخدم في الخطوة التالية القوالب لعرض المحتوى إلى المستخدمين. الخطوة الثالثة - خدمة ملفات القوالب القوالب هي ملفات لعرض محتوى ثابت وحيوي لزوار تطبيقك، في هذه الخطوة، سننشئ قالب HTML لإنشاء الصفحة الرئيسية لتطبيقك. إبدأ بإنشاء ملف home.html في مجلد app/templates: sudo nano app/templates/home.html أضف الشيفرة البرمجية إلى قالبك لإنشاء صفحة HTML5 تحتوي على عنوان وبعض النصوص. الملف ‎/var/www/TestApp/app/templates/home.html: <!doctype html> <html lang="en-us"> <head> <meta charset="utf-8"> <meta http-equiv="x-ua-compatible" content="ie=edge"> <title>Welcome home</title> </head> <body> <h1>Home Page</h1> <p>This is the home page of our application.</p> </body> </html> بعد ذلك، عدّل على ملف app/views.py لخدمة الملف المنشئ حديثًا: sudo nano app/views.py أضف أولا السطر التالي إلى بداية ملفك لإستدعاء أسلوب render_template من Flask والذي يرمّز صفحة HTML لتصيير (render) صفحة ويب للمستخدم. from flask import render_template ... أضف مسار (route) آخر في نهاية الملف لتصيير ملف القالب حيث ستحدّد هذه الشيفرة البرمجية أن المستخدمين سيخدمون بمحتوى ملف home.html عند زيارة مسار ‎/template في تطبيقك. ... @app.route('/template') def template(): return render_template('home.html') سيبدو ملف app/views.py بعد تحديثه كالتالي: from flask import render_template from app import app @app.route('/') def home(): return "Hello world!" @app.route('/template') def template(): return render_template('home.html') من أجل تفعيل هذه التغييرات، ستحتاج إلى إيقاف وإعادة تشغيل حاويات Docker. شغّل الأمر التالي لإعادة بناء الحاوية: sudo docker stop docker.test && sudo docker start docker.test زر تطبيقك الآن على http://your-ip-address:56733/template لمشاهدة خدمة القالب الجديد. في هذه الخطوة أنشأت ملف قالب Docker لخدمة زوار تطبيقك وفي الخطوة القادمة سنرى كيف يمكنك تفعيل التغييرات دون الحاجة إلى إعادة تشغيل حاوية Docker. الخطوة الرابعة - تحديث التطبيق ستحتاج في بعض الأحيان إلى القيام ببعض التغييرات في تطبيقك مثل تثبيت متطلبات جديدة، تحديث حاوية Docker أو تغيير شيفرة HTML أو المنطق، لذلك، سنتحدّث الآن عن إعداد touch-reload للقيام بهذه التغييرات دون الحاجة إلى إعادة تشغيل حاوية Docker. يراقب بايثون autoreloading نظام الملفات للتغييرات وتحديث التطبيق عند إيجاد تغيير، وهذه العملية غير منصوح بها عند مرحلة الإنتاج (production) لأنها ستستهلك الكثير من الموارد. سنستخدم touch-reload لمراقبة التغييرات لملف معيّن وإعادة التحميل عند تحديث أو استبدال هذا الملف. لفعل ذلك، نبدأ بفتح ملف uwsgi.ini: sudo nano uwsgi.ini ونضيف هذا السطر الأخير إلى نهاية ملف uwsgi.ini كما هو موضح في الشيفرة التالية: module = main callable = app master = true touch-reload = /app/uwsgi.ini يحدد هذا السطر الملف الذي يجب التعديل عليه لإعادة تحميل كامل التطبيق. لمشاهدة هذا، غيّر قليلا في تطبيقك، فعلى سبيل المثال، افتح ملف app/views.py: sudo nano app/views.py استبدل السلسلة النصيّة التي تعود من الدالة home: from flask import render_template from app import app @app.route('/') def home(): return "<b>There has been a change</b>" @app.route('/template') def template(): return render_template('home.html') والآن، إذا فتحت الصفحة الرئيسية لتطبيقك على http://ip-address:56733 ستلاحظة عدم ظهور التغييرات، وهذا بسبب أن شرط إعادة التحميل هو تغيير ملف uwsgi.ini، لذا استخدم touch لتفعيل هذا الشرط: sudo touch uwsgi.ini أعد تحميل صفحة الرئيسية في تطبيقك على متصفحك مرّة أخرى، ستظهر لك التغييرات: في هذه الخطوة، أعددت شرط touch-reload لتحديث تطبيقك بعد القيام بتغييرات. الخلاصة في هذا الدرس، أنشأت ونشرت تطبيق Flask على حاوية Docker، ولقد أعددّت touch-reload لإعادة تحميل التطبيق دون الحاجة إلى إعادة تشغيل الحاوية. يمكنك الآن التوسع أكثر واكتشاف Docker بطريقة معمّقة، ويمكنك البدء بالتوثيق الرسمي ترجمة -وبتصرف- للمقال How To Build and Deploy a Flask Application Using Docker on Ubuntu 18.04 لصاحبه Michael Okoh
  5. سنتحدث في درسنا الأخير من هذه السلسلة عن إنشاء القوائم ul-li، وكيف نطبق القالب على القوائم المرتبة وغير المرتبة، وسنشرح كيف نستخدم الصورة المصغرة (thumbnails) والأيقونات في القوائم، وكيف ننشئ نماذج البحث وتسجيل الدخول باستخدام عناصر النموذج، ويأتي كل هذا مع مقتطفات من الشيفرة البرمجية. هذا الدرس جزء من سلسلة دروس تشرح jQuery Mobile: الدرس الأول: البداية، بناء وتقديم محتوى الدرس الثاني: التضمين، تهيئة الصفحة، التنقل بين الصفحات وأحداث التحميل الدرس الثالث: اتجاه الصفحة وأحداثها الدرس الرابع: ربط صفحات خارجية وتنظيم المحتوى بنظام الشبكة وبناء محتوى قابل للطي الدرس الخامس: الأيقونات والأزرار وإنشاء تنسيقات مخصصة الدرس السادس: إنشاء القوائم وتنسيقها وإنشاء نماذج البحث وتسجيل الدخول إنشاء قائمة قياسية يمكنك باستخدام HTML إنشاء قائمة قياسية عن طريق إنشاء عنصر ul ووضع عناصر li داخله، وستتبع نفس الخطوات لإنشاء قائمة قياسية في jQuery Mobile وستحتاج إلى إضافة الخاصية data-role="listview"‎ إلى عنصر ul. المثال 51: القوائم باستخدام jQuery Mobile <!DOCTYPE html> <html> <head> <title>Script-Tutorials: Listing with jQuery Mobile</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" /> <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script> <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script> </head> <body> <div data-role="page"> <div data-role="header"> <h1>Listing using jQuery Mobile</h1> </div> <div data-role="content"> <ul data-role="listview"> <li data-role="list-divider">List Items</li> <li>I am a list item!</li> <li>I am another list item!</li> <li data-role="list-divider">List Items with Links</li> <li><a href="#">I am a link in a list item!</a> </li> <li><a href="#">I am another link in a list item!</a> </li> </ul> </div> </div> </body> </html> تطبيق قالب على شكل عناصر القائمة لإضافة المرونة إلى شكل القائمة، تملك jQuery Mobile بعض خاصيات data لتنسيق الحاويات وفقاعات العد (count bubbles) وأزرار التقسيم (split buttons). لتطبيق قالب على قائمة مقسمة (list divider)، يمكنك إما تطبيق الخاصية data-theme مباشرةً أو يمكنك استخدام الخاصية data-divider-theme التي تطبقها على وسم ul الرئيسي. بالنسبة لفقاعات العد، استخدم الخاصية data-count-theme التي يمكنك وضعها على الوسم ul لتطبيق القالب على جميع فقاعات العد في القائمة، أو إلى عناصر فردية لتحديد الفرق بين قوائم عدّ القوالب المختلفة داخل قائمة معينة. استخدم الخاصيتين data-split-theme و data-split-icon لقالب أزرار التقسيم. تسمح لك الخاصية data-split-theme بتحديد القالب للزر الصحيح في أزرار التقسيم، ويمكنك تطبيقها إما على ul أو على عناصر فردية في القائمة. مثال 52: استخدام قوالب jQuery في مكونات القائمة <!DOCTYPE html> <html> <head> <title>Script-Tutorials: Cutomized icons in jQuery Mobile</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" /> <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script> <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script> </head> <body> <section id="swatch-e" data-role="page" data-theme="e"> <header data-role="header" data-theme="e"> <h1>jQuery Mobile</h1> </header> <div class="content" data-role="content"> <h3>Theming list view elements</h3> <ul data-role="listview" data-split-icon="star" data-divider-theme="e" data-count-theme="a"> <li data-role="list-divider">Tutorial courses<span class="ui-li-count">3</span> </li> <li><a href="application.php">Microsoft Application</a><a href="order.php">Make order</a> </li> <li><a href="suite.php">Graphic suite</a><a href="apply.php">Apply now</a> </li> <li><a href="dkit.php">Developers kit</a><a href="request.php">Request now</a> </li> </ul> </div> <footer data-role="footer"> <h1>footer</h1> </footer> </section> </body> </html> إنشاء قائمة مركّبة لإنشاء قائمة مركبة (inset list) تفاعلية (تشبه عناصرها الأزرار)، ابدأ بإنشاء قائمة قياسية وأضف إليها الخاصية data-inset="true"‎ إلى عنصر ul. غيرنا السطر الأول لجعل القائمة مركبة: <ul data-role="listview" data-inset="true"> مثال 53: إنشاء قائمة مركّبة <!DOCTYPE html> <html> <head> <title>Script-Tutorials: Listing with jQuery Mobile</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" /> <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script> <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script> </head> <body> <div data-role="page"> <div data-role="header"> <h1>Listing using jQuery Mobile</h1> </div> <div data-role="content"> <ul data-role="listview" data-inset="true"> <li data-role="list-divider">List Items</li> <li>I am a list item!</li> <li>I am another list item!</li> <li data-role="list-divider">List Items with Links</li> <li><a href="#">I am a link in a list item!</a> </li> <li><a href="#">I am another link in a list item!</a> </li> </ul> </div> </div> </body> </html> استخدام قائمة مرتَّبة تحتاج إلى البدء بعنصر ol وتضمين li داخله لإنشاء قائمة مرتبة. كل عنصر li سيُرقَّم تلقائيًّا بناءً على ترتيبه في القائمة. مثال 54: استخدام jQuery Mobile لإنشاء قائمة مرتبة <!DOCTYPE html> <html> <head> <title>Script-Tutorials: Listing with jQuery Mobile</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" /> <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script> <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script> </head> <body> <div data-role="page"> <div data-role="header"> <h1>Listing using jQuery Mobile</h1> </div> <div data-role="content"> <ol data-role="listview"> <li data-role="list-divider">Numbered List Items with Links</li> <li><a href="#">Polar</a> </li> <li><a href="#">Grizzly</a> </li> <li><a href="#">Brown</a> </li> <li><a href="#">Black</a> </li> </ol> </div> </div> </body> </html> مثال 55: استخدام jQuery Mobile لإنشاء قائمة مركبة مرتبة في حين لم تُعد القائمة المرتبة كقائمة مركبة مرتبة، إلا أنه يمكنك إنشاء واحدة باستخدام الخاصية data-inset="true"‎ على العنصر ol. <!DOCTYPE html> <html> <head> <title>Script-Tutorials: Listing with jQuery Mobile</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" /> <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script> <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script> </head> <body> <div data-role="page"> <div data-role="header"> <h1>Listing using jQuery Mobile</h1> </div> <div data-role="content"> <ol data-role="listview" data-inset="true"> <li data-role="list-divider">Numbered List Items with Links</li> <li><a href="#">Polar</a> </li> <li><a href="#">Grizzly</a> </li> <li><a href="#">Brown</a> </li> <li><a href="#">Black</a> </li> </ol> </div> </div> </body> </html> إضافة عداد إلى القائمة في jQuery Mobile يحظى هذا النمط بشعبية في تطبيقات الرسائل أو البريد الإلكتروني لعرض رقم العناصر أو حساب عدد العناصر الموجودة في القسم الفرعي أو رابط، ويمكنك تكرار هذا النمط باستخدام عنصر يحتوي على الخاصية class="ui-li-count"‎ داخل عناصر li. مثال 56: استخدام jQuery Mobile لوضع عداد في قائمة قياسية <!DOCTYPE html> <html> <head> <title>Script-Tutorials: Listing with jQuery Mobile</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" /> <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script> <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script> </head> <body> <div data-role="page"> <div data-role="header"> <h1>Listing using jQuery Mobile</h1> </div> <div data-role="content"> <ul data-role="listview"> <li data-role="list-divider">List Items with Links and a Count</li> <li><a href="#">Bugs<span class="ui-li-count">5</span></a> </li> <li><a href="#">Comments<span class="ui-li-count">12</span></a> </li> <li><a href="#">Suggestions<span class="ui-li-count">8</span></a> </li> <li><a href="#">Tickets<span class="ui-li-count">27</span></a> </li> </ul> </div> </div> </body> </html> إضافة الأيقونات والصور المصغرة إلى عناصر قائمة باستخدام jQuery عند تصميم قائمتك، قد ترغب في تضمين أيقونة أو صورة مصغرة مع كل عنصر في القائمة، وهذا ليس ممكنا فقط بل سهل أيضًا. إضافة صورة مصغّرة الصورة المصغّرة هي معاينة أو نسخة صغيرة من صورة أكبر، ويمكنك إضافة الصور المصغرة إلى عناصر القائمة عن طريق تضمينها داخل عنصر a في عنصر li. مثال 57: استخدام jQuery Mobile لإضافة صور مصغرة إلى عناصر القائمة <!DOCTYPE html> <html> <head> <title>Script-Tutorials: Listing with jQuery Mobile</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" /> <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script> <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script> </head> <body> <div data-role="page"> <div data-role="header"> <h1>Listing using jQuery Mobile</h1> </div> <div data-role="content"> <ul data-role="listview"> <li data-role="list-divider">List Items with Links and Thumbnails</li> <li> <a href="#"><img src="images/virgin.jpg" alt="A Virgin" />Virgin</a> </li> <li> <a href="#"><img src="images/tear.jpg" alt="Tears" />Tears</a> </li> <li><img src="images/scholar.jpg" alt="Scholars" />Scholars</li> <li><img src="images/studying.jpg" alt="Study" />Study</li> </ul> </div> </div> </body> </html> إضافة أيقونات إلى عناصر قائمة المثال 58: استخدام jQuery Mobile لإضافة أيقونات إلى عناصر القائمة <!DOCTYPE html> <html> <head> <title>Script-Tutorials: Listing with jQuery Mobile</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" /> <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script> <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script> </head> <body> <div data-role="page"> <div data-role="header"> <h1>Listing using jQuery Mobile</h1> </div> <div data-role="content"> <ul data-role="listview"> <li data-role="list-divider">List Items with Links and Thumbnails</li> <li> <a href="#"><img class="ui-li-icon" src="images/virgin.jpg" alt="A Virgin" />Virgin</a> </li> <li> <a href="#"><img class="ui-li-icon" src="images/tear.jpg" alt="Tears" />Tears</a> </li> <li><img class="ui-li-icon" src="images/scholar.jpg" alt="Scholars" />Scholars</li> <li><img class="ui-li-icon" src="images/studying.jpg" alt="Study" />Study</li> </ul> </div> </div> </body> </html> إنشاء قائمة مقسمة القائمة المقسمة (split list) هي قائمة تحتوي على عناصر تملك أكثر من رابط واحد. عندما تضيف عنصرين داخل عنصر li، يُنشئ jQuery Mobile قائمة مقسمة تلقائيًا. يأخذ العنصر الأول معظم مساحة عنصر القائمة تاركًا العنصر الثاني كقسم صغير مع مساحة لأيقونة على الجانب الأيمن من عنصر القائمة. بما أن القوائم المقسمة التي تنشئ تلقائيًا بإضافة رابطٍ ثانٍ، يمكنك خلط قوائم إضافية أخرى معًا. مثال 59: استخدام jQuery Mobile لإنشاء قائمة مقسمة <!DOCTYPE html> <html> <head> <title>Script-Tutorials: Listing with jQuery Mobile</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" /> <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script> <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script> </head> <body> <div data-role="page"> <div data-role="header"> <h1>Listing using jQuery Mobile</h1> </div> <div data-role="content"> <ul data-role="listview" data-split-theme="e"> <li data-role="list-divider">Split List</li> <li> <a href="#"> <h3>First link in a split list</h3> <p>The icon on the right is the default icon</p> </a> <a href="#" title="Second Link">Second link in a split list</a> </li> <li> <a href="#"> <img class="ui-li-icon" src="images/cable_car2.jpg" alt="Cars on route" /> <h3>Use with an icon</h3> <p>Yep, you can use icons with split lists</p> </a> <a href="#" title="Another link">Another split list link</a> </li> <li> <a href="#"> <img src="images/cable_car1.jpg" alt="Cars on wires" /> <h3>Use with a thumbnail</h3> <p>Wow, you can also use thumbnails in split lists.</p> </a> <a href="#" title="Titles are accessible">Another split list link</a> </li> </ul> </div> </div> </body> </html> محتوى قائمة البحث إذا كنت تستخدم القائمة لعرض عدد كبير من العناصر فيمكنك إرفاق مرشّح بحث لمساعدة المستخدمين في التنقل لإيجاد ما يريدون. إن إنشاء مرشّح البحث أسهل مما تعتقد، فكل ما يجب عليك فعله هو إضافة الخاصية data-filter="true"‎ إلى عنصر ul في قائمتك. مثال 60: استخدام jQuery Mobile لإنشاء محتوى قائمة البحث <!DOCTYPE html> <html> <head> <title>Script-Tutorials: Listing with jQuery Mobile</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" /> <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script> <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script> </head> <body> <div data-role="page"> <div data-role="header"> <h1>Listing using jQuery Mobile</h1> </div> <div data-role="content"> <ul data-role="listview" data-filter="true"> <li data-role="list-divider">Secondary Names</li> <li>Okeagu Chioma</li> <li>Nonso Diobi(S.P)</li> <li>Ikenna Okoye</li> <li>Agu Chidera</li> <li>Onyeka Ibezim</li> <li>Maduka Abum</li> <li>Felix Onah</li> <li>Mmadueke Oluchukwu</li> <li>Nneka Ebeonadi</li> <li>Cosmas Ugwuoke</li> <li>Chisom Okonkwo</li> <li>Marvelous Nnaemeka</li> <li>Umenna Julius</li> <li>Leonard Onah</li> <li>Ferdinand Okoro</li> <li>Shedrack Onah</li> <li>Umenna Vera</li> </ul> </div> </div> </body> </html> تخصيص مرشح بحث عن نصوص في قائمة مركبة مثال 61: استخدام jQuery Mobile لإنشاء مرشح بحث عن نصوص في قائمة مركبة <!DOCTYPE html> <html> <head> <title>Script-Tutorials: Listing with jQuery Mobile</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" /> <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script> <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script> </head> <body> <div data-role="page"> <div data-role="header"> <h1>Listing using jQuery Mobile</h1> </div> <div data-role="content"> <ul data-role="listview" data-filter="true" data-filter-placeholder="Find Album..." data-inset="true"> <li data-role="list-divider">Adice</li> <li>Punishment</li> <li>Disgrace</li> <li>Disdain</li> <li>Insult</li> <li>Angry</li> <li>Ways mobile jQuery</li> </ul> </div> </div> </body> </html> تحسين النماذج مع jQuery Mobile يدعم jQuery Mobile النماذج (forms) في أجهزة الهاتف، فأُعيد صقل كل عنصر ليكون متاحًا ويمكن استخدامه بسهولة على أجهزة الهاتف، ضع في اعتبارك أن بعض أنماط النماذج تختلف قليلا على المنصة ومتصفح الهاتف الذي تستخدمه. مثال 62: استخدام jQuery Mobile لبناء نموذج تسجيل دخول بسيط <!DOCTYPE html> <html> <head> <title>Script-Tutorials: Forms with jQuery Mobile</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" /> <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script> <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script> </head> <body> <div data-role="page"> <div data-role="header"> <h1>Forms in jQuery Mobile</h1> </div> <div data-role="content"> <form id="login" name="login" action="login.php" method="POST"> <label for="username">Username: </label> <input type="text" name="username" id="username" value="" /> <br /> <label for="password">Password:</label> <input type="password" name="password" id="password" value="" /> <br /> <input type="hidden" name="hiddenInput" id="hiddenInput" value="secret message" /> <input type="submit" name="loginSubmit" id="loginSubmit" value="Login" /> </form> </div> </div> </body> </html> مثال 63: استخدام الخاصية data-role="fieldcontain"‎ لترصيف العناصر في نموذج تسجيل الدخول البسيط لاحظ أن هنالك فرق بسيط في الشيفرة البرمجية عن سابقه <!DOCTYPE html> <html> <head> <title>Script-Tutorials: Forms with jQuery Mobile</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" /> <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script> <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script> </head> <body> <div data-role="page"> <div data-role="header"> <h1>Forms in jQuery Mobile</h1> </div> <div data-role="content"> <form id="login" name="login" action="login.php" method="POST"> <div data-role="fieldcontain"> <label for="username">Username: </label> <input type="text" name="username" id="username" value="" /> <br /> </div> <div data-role="fieldcontain"> <label for="password">Password:</label> <input type="password" name="password" id="password" value="" /> <br /> </div> <input type="hidden" name="hiddenInput" id="hiddenInput" value="secret message" /> <input type="submit" name="loginSubmit" id="loginSubmit" value="Login" /> </form> </div> </div> </body> </html> تظهر الصورة في أسفل العناصر المنظمة لنموذج تسجيل الدخول البسيط الآن رأينا استخدام عناصر النص، دعنا نلقي نظرة على بعض عناصر الإدخال الأخرى في jQuery Mobile. أزرار الانتقاء ومربعات الاختيار ستفيدك أزرار الانتقاء عندما ترغب في تقديم أكثر من خيار واحد إلى المستخدم لكن يجب عليه أن يختار أحدها فقط، ويشبه ذلك اختبارات متعددة الاختيار أو نماذج "ملء الفقاعة". أزرار الانتقاء في jQuery Mobile متطورة أكثر من أزرار الانتقاء القياسية عبر استخدام عنصر التسمية لعرض زر الانتقاء على شريط سهل اللمس. يجب عليك لإنشاء زر انتقاء البدء بإنشاء عنصر الإدخال واستخدام الخاصية type="radio"‎. وقد ترغب أيضا بإعطاء زر الانتقاء خاصية القيمة والمُعرّف. لجعل أزرار الانتقاء متعددة تعمل معًا، يجب عليك إعطائها جميعًا نفس الاسم، أي يجب أن يشبه زر الانتقاء لهذا المقتطف: <input type="radio" name="radio-1" id="radio-1" value="Option 1" /> يمكنك جمع أزرار الانتقاء معًا داخل عنصر div أو عنصر fieldset باستخدام controlgroup، وسيعرضون دون فواصل بينها. إذا استخدمت عنصر fieldset فيمكنك أيضا استخدام عنصر legend لإعطاء وصف للمجموعة. إذا أردت عرض أزرار الانتقاء بشكل أفقي يمكنك استخدام الخاصية data-role="controlgroup"‎ والخاصية data-type="horizontal"‎ لكن ستكون أزرار الانتقاء كصف من الأزرار القياسية عوضًا عن سطر من أزرار الانتقاء. تشبه مربعات الاختيار أزرار الانتقاء، لكنها تسمح للمستخدم باختيار العدد الذي يرغب به من العناصر بدلا من تحديد عنصر واحد. وتمامًا مثل أزرار الانتقاء، يجب عليك إرفاق عنصر واصف (label) لكل عنصر checkbox حتى يتمكن jQuery Mobile من إنشاء شريط سهل اللمس. يجب عليك لإنشاء مربعات الاختيار البدء بعنصر الإدخال وإضافة الخاصية type="checkbox"‎، ويجب أن يشبه مربع الاختيار لهذا المقتطف: <input type="checkbox" name="checkbox-1" id="checkbox-1" /> يمكنك جمع مربعات الاختيار معا باستخدام عنصر الحاوية (container) مع الخاصية data-role="controlgroup"‎. مثال 64: إنشاء أزرار انتقاء ومربعات الاختيار في نموذج باستخدام jQuery Mobile. <!DOCTYPE html> <html> <head> <title>Script-Tutorials: Forms with jQuery Mobile</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" /> <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script> <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script> </head> <body> <div data-role="page"> <div data-role="header"> <h1>Forms in jQuery Mobile</h1> </div> <div data-role="content"> <form id="login" name="login" action="login.php" method="POST"> <div class="ui-grid-a"> <div class="ui-block-a"> <fieldset> <legend>Radio Buttons:</legend> <input type="radio" name="radio-group-1" id="radio1" value="Male" checked="checked" /> <label for="radio1">Male</label> <input type="radio" name="radio-group-1" id="radio2" value="Female" /> <label for="radio2">Female</label> </fieldset> <fieldset data-role="controlgroup"> <legend>Using a controlgroup:</legend> <input type="radio" name="radio-group-2" id="radio3" value="Boy" checked="checked" /> <label for="radio3">Boy</label> <input type="radio" name="radio-group-2" id="radio4" value="Girl" /> <label for="radio4">Girl</label> </fieldset> </div> <div class="ui-block-b"> <fieldset> <legend>Checkboxes:</legend> <input type="checkbox" name="checkbox-1" id="checkbox-1" /> <label for="checkbox-1">Advice</label> <input type="checkbox" name="checkbox-2" id="checkbox-2" /> <label for="checkbox-2">Condemn</label> </fieldset> <fieldset data-role="controlgroup"> <legend>Grouping checkboxes:</legend> <input type="checkbox" name="checkbox-3" id="checkbox-3" /> <label for="checkbox-3">Microsoft</label> <input type="checkbox" name="checkbox-4" id="checkbox-4" /> <label for="checkbox-4">Adobe</label> </fieldset> </div> </div> </form> </div> </div> </body> </html> العنصر select يختلف العنصر select قليلا عن بقية العناصر لأنه لا يقوم بتمديد عنصر الإدخال، وبدلا من ذلك يتصرف كحاوي لعناصر الخيارات. كل عنصر اختيار لديه قيمة ويحتوي على نص، ويظهر هذا النص عند الضغط عليه أو لمس العنصر select، وعندما يرى المستخدم عناصر الخيارات ويختار واحد منها، ستصبح قيمته هي قيمة العنصر select. نمط عنصر الاختيار في jQuery Mobile هو زر مع سهم يشير للأسفل، كما أنه يأخذ مساحة كبيرة حسب ما يتاح له و يمكن استخدامه مع حاوية تملك الخاصية data-role="fieldcontain"‎ لوضع تسمية وتحديد العناصر على نفس السطر (إذا كان هنالك مساحة كافية على الشاشة). مثال 65: استخدام jQuery Mobile لإنشاء عنصر select في نموذج <!DOCTYPE html> <html> <head> <title>Script-Tutorials: Forms with jQuery Mobile</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" /> <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script> <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script> </head> <body> <div data-role="page"> <div data-role="header"> <h1>Forms in jQuery Mobile</h1> </div> <div data-role="content"> <form id="login" name="login" action="login.php" method="POST"> <label for="size-select">Select your Size:</label> <select name="size-select" id="size-select"> <option value="small">small</option> <option value="medium">medium</option> <option value="large">large</option> </select> <div data-role="fieldcontain"> <label for="radius-select">Choose a Radius</label> <select name="radius-select" id="radius-select"> <option value="radius-5">5</option> <option value="radius-15">15</option> <option value="radius-25">25</option> </select> </div> <div data-role="fieldcontain"> <fieldset data-role="controlgroup" data-type="horizontal"> <legend>Set Time:</legend> <label for="hour-select">Hour</label> <select name="hour-select" id="hour-select"> <option>Hour</option> <option value="hour-08">08</option> <option value="hour-09">09</option> <option value="hour-10">10</option> </select> <label for="minute-select">Minute</label> <select name="minute-select" id="minute-select"> <option>Minute</option> <option value="minute-10">10</option> <option value="minute-20">20</option> <option value="minute-30">30</option> </select> </fieldset> </div> </form> </div> </div> </body> </html> عناصر إدخال إضافية تملك أجهزة الهاتف طرقًا أخرى جديدة لجمع مدخلات المستخدم، كان بعضها موجود لمتصفحات حواسيب سطح المكتب لبعض الوقت، لكن لم تُستخدم كفاية لتُعتبر شائعة. عند التفكير في ميزات التحكم أو الإدخال المختلفة للهاتف، غالبا ما ستتضمن شريط تمرير لتغيير الإعدادات، مفتاح تبديل إعداد إلى آخر وميزة البحث، وكلها مدعومة في jQuery Mobile. شريط التمرير (slider) يُستخدم شريط التمرير في الصفحات التي يجب فيها على المستخدم أن يضغط/يلمس ويسحب لتحديد قيمة بدلا من كتابتها، وهذا يجعل لشريط التمرير فوائد كثيرة كالتحكم في مستوى الصوت، أو السطوع، أو حتى للاستخدام على الصفحات التي تقوم بعمليات حسابية. ألق نظرة على الشيفرة البرمجية التالية وحاول معرفة ما تفعله كل خاصية: <input type="range" name="slider" id="slider" value="10" min="0" max="100" /> يبحث jQuery Mobile على type="range"‎ لإنشاء شريط التمرير، ونعم، حتى لو كان نوعه type="range"‎ فهو شريط تمرير. لا يوجد شيء مميز حول الخاصيتين name و id، فهما يعملان بنفس الطريقة التي تعمل بها عناصر الإدخال الأخرى. ومع ذلك، فإن الخاصية value مهمة لأنها تحدد أين يبدأ زر المنزلق/المقبض. تحدد الخاصية min أقل قيمة يمكن الوصول إليها. وأما الخاصية max فهي تحدد أقصى قيمة مسموح بها. يجب عليك استخدام تسمية مع كل شريط تمرير تُضمّنه في صفحتك، وينبغي أن يتم هذا ليس فقط للعرض وقابلية الوصول، بل لأنه مطلوب عند استخدام jQuery Mobile. مثال 66: استخدام jQuery mobile لإضافة أشرطة تمرير داخل النموذج <!DOCTYPE html> <html> <head> <title>Script-Tutorials: Forms with jQuery Mobile</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" /> <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script> <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script> </head> <body> <div data-role="page"> <div data-role="header"> <h1>Forms in jQuery Mobile</h1> </div> <div data-role="content"> <form id="volume" name="volume" action="volume.php"> <div data-role="fieldcontain"> <label>Bass:</label> <input type="range" name="" id="" min="10" max="110" value="80" /> </div> <div data-role="fieldcontain"> <label>Mid:</label> <input type="range" name="" id="" min="0" max="90" value="80" /> </div> <div data-role="fieldcontain"> <label>Treble:</label> <input type="range" name="" id="" min="5" max="105" value="80" /> </div> </form> </div> </div> </body> </html> زر القاطعة (flip toggle switch) يشبه زر القاطعة عملية النفي الثنائية (not) المطبقة على بت واحد، إما أنه مشتغل (on) أو أنه مطفأ (off)، وهذا المفتاح شائع في الإعدادات حيث يمكنك تشغيل أجزاء مختلفة من الهاتف أو تطفئها. ستحتاج لإنشاء زر القاطعة إلى البدء بعنصر select يملك عنصري option، ومن ثم تضيف الخاصية data-role="slider"‎ إلى العنصر select. وكما في عناصر الإدخال الأخرى، يمكنك وضع الزر داخل حاوية باستخدام data-role="fieldcontain"‎ لإبقاء التسمية والزر في نفس السطر (إذا كانت المساحة متوفرة). مثال 67: استخدام jQuery Mobile لإنشاء زر قاطعة <!DOCTYPE html> <html> <head> <title>Script-Tutorials: Forms with jQuery Mobile</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" /> <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script> <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script> </head> <body> <div data-role="page"> <div data-role="header"> <h1>Flip in Forms using jQuery Mobile</h1> </div> <div data-role="content"> <form id="flip" name="flip" action="flipswitch.php"> <label for="flip-1">Brightness:</label> <select name="flip-1" id="flip-1" data-role="slider"> <option value="Bright">Bright</option> <option value="Dark">Dark</option> </select> <div data-role="fieldcontain"> <label for="flip-2">Flip switch:</label> <select name="flip-2" id="flip-2" data-role="slider"> <option value="Loud">Loud</option> <option value="Silent">Silent</option> </select> </div> </form> </div> </div> </body> </html> حقل البحث حقل البحث هو نوع جديد من المدخلات والذي هو جزء من مميزات HTML5، هذا الحقل هو حقل نص مُحسّن يحتوي على أيقونة لمساعدة المستخدمين على معرفة ما هو عليه، وعندما يبدأ المستخدم بكتابة شيء معين ستظهر أيقونة عند الضغط عليها أو لمسها ستحذف جميع مدخلات نص المستخدم في الحقل. لإنشاء حقل بحث، استخدم هذا المقتطف: <input type="search" name="search-input" id="search-input" value="" /> كما في العناصر الأخرى التي تناولناها حتى الساعة، تأكد من تضمين التسمية (label) لزيادة إمكانية الوصول إلى النموذج، ويمكنك أيضا استخدام حاوية مع data-role="fieldcontain"‎ لإبقاء التسمية وحقل البحث في نفس السطر إذا كانت هنالك مساحة كافية على الشاشة. مثال 68: إنشاء حقل بحث باستخدام jQuery Mobile <!DOCTYPE html> <html> <head> <title>Script-Tutorials: Forms with jQuery Mobile</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" /> <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script> <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script> </head> <body> <div data-role="page"> <div data-role="header"> <h1>Search in Forms using jQuery Mobile</h1> </div> <div data-role="content"> <form id="search-form" name="search-form" action="search.php" method="get"> <label for="search-1">Search the site:</label> <input type="search" name="search-1" id="search-1" value="" /> <div data-role="fieldcontain"> <label for="search-2">Find:</label> <input type="search" name="search-2" id="search-2" value="" /> </div> </form> </div> </div> </body> </html> استخدام الإضافات يمكنك إضافة الإضافات بطرق مختلفة لأنها تغطي أي شيء ترغب في إضافته إلى المكتبة الرئيسية. بعض الإضافات عبارة على ملفات JavaScript التي تُضمّنها مع jQuery Mobile، والأخريات هي عبارة عن ملفات CSS إضافية. سنلقي نظرة سريعة على استخدام إضافة 960 شبكة (960 grid) مع صفحة تستخدم jQuery Mobile. إن ‏960‏ grid‏‏ عبارة عن نظام شبكة مشهور في مواقع ويب سطح المكتب، فهي تسمح للصفحات بأن تكون مرنة وتسمح للمحتوى بالتمدد والتقلص استنادًا إلى المساحة القابلة للعرض في المتصفح. Jquery Mobile هو بوابة لإضافة 960 grid لهذا النظام ويمكنك الحصول عليها من هنا. مثال 69: استخدام إضافات jQuery Mobile في إعدادات شيفرة HTML قياسية <!DOCTYPE html> <html> <head> <title>Developing with jQuery Mobile</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" /> <link rel="stylesheet" href="http://jeromeetienne.github.com/jquery-mobile-960/css/jquery-mobile-fluid960.min.css" /> <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script> <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script> </head> <body> <div data-role="page"> <div data-role="header"> <h1>960gs plugin example</h1> </div> <div data-role="content"> <div class="container_12"> <div class="grid_2"><a href="#" data-role="button">2 column</a> </div> <div class="grid_6"> <a href="#" data-role="button">6 column</a> <p>The fluid grid allows this layout to adapt to screen size</p> <p>You can see how it adjusts by changing device orientation</p> <p>When orientation changes, the size of the columns changes</p> </div> <div class="grid_4"> <a href="#" data-role="button">4 column</a> </div> </div> </div> </div> </body> </html> عرض تجريبي: تخطيط مواقع بسيطة لكن متجاوبة العرض التجريبي الأول: تخطيط ومعاينة موقع ملف عرض تجريبي 2: تخطيط الأجهزة اللوحية عرض تجريبي 3: تخطيط سطح المكتب عرض تجريبي 4: مثال jQuery Mobile بسيط ترجمة -وبتصرّف- للمقال jQuery Mobile Lesson 6 لصاحبه Andrew اقرأ أيضًا الدرس السابق: الأيقونات والأزرار وإنشاء تنسيقات مخصصة إنشاء تطبيقات ويب ذات صفحة وحيدة باستخدام jQuery
  6. في درسنا الخامس اليوم، سنتحدث عن المجموعة المدمجة من الأيقونات، ووضع الأيقونة، وإنشاء أزرار مخصصة، واستخدام النماذج اللونية (swatches)، وإنشاء قوالب مخصصة …إلخ. جميع الأمثلة ستكون مدعومة بمقتطفات من الشيفرة البرمجية. هذا الدرس جزء من سلسلة دروس تشرح jQuery Mobile: الدرس الأول: البداية، بناء وتقديم محتوى الدرس الثاني: التضمين، تهيئة الصفحة، التنقل بين الصفحات وأحداث التحميل الدرس الثالث: اتجاه الصفحة وأحداثها الدرس الرابع: ربط صفحات خارجية وتنظيم المحتوى بنظام الشبكة وبناء محتوى قابل للطي الدرس الخامس: الأيقونات والأزرار وإنشاء تنسيقات مخصصة الدرس السادس: إنشاء القوائم وتنسيقها وإنشاء نماذج البحث وتسجيل الدخول إضافة الأيقونات إلى الأزرار تسمح لنا هذه الصور أو الأيقونات معرفة ما هو الزر دون الحاجة إلى قراءة محتواه الذي يدل على وظيفته، كما أنها تجعل بعض الأزرار تظهر يحجم أقل إذا لم يكن هنالك مساحة كافية الأمر الذي يساعد على توضيح ما يفترض القيام به. استخدام مجموعة الأيقونات المضمنة في jQuery يأتي jQuery Mobile مع مجموعة مدمجة من الأيقونات التي يمكنك استخدامها على أزرارك لتساعدك على جعل التصميم أفضل لأجهزة الهاتف. يمكنك تطبيق هذه الأيقونات على الأزرار بإضافة الخاصية data-icon=""‎ إلى العنصر الذي تستخدمه كزر. القيمة الموجودة في هذه الخاصية هي الأيقونة التي تريد عرضها في الزر؛ فعلى سبيل المثال، إذا أردت عرض أيقونة البحث في الزر استخدم الخاصية data-icon="search"‎ على العنصر الذي تستخدمه كزر. الأيقونات الموجودة هي: السهم الأيسر – data-icon="arrow-l"‎ السهم الأيمن – data-icon="arrow-r"‎ السهم العلوي – data-icon="arrow-u"‎ السهم السفلي – data-icon="arrow-d"‎ حذف – data-icon="delete"‎ الجمع – data-icon="plus"‎ الطرح – data-icon="minus"‎ التأكد – data-icon="check"‎ أداة – data-icon="gear"‎ التحديث – data-icon="refresh"‎ التقدم إلى الأمام – data-icon="forward"‎ الرجوع إلى الخلف – data-icon="back"‎ الشبكة – data-icon="grid"‎ نجمة – data-icon="star"‎ إنذار – data-icon="alert"‎ معلومة – data-icon="info"‎ منزل – data-icon="home"‎ بحث – data-icon="search"‎ مثال 38: إضافة أيقونات إلى الزر يمكن إنشاء أزرار الروابط عن طريق استخدام -role="button"‎. يملك كل زر أيقونة مختلفة عن طريق استخدام data-icon="back"‎، و dataicon="home"‎، و data-icon="forward"‎ وسيضيف هذا أيقونات jQuery الافتراضية إلى الأزرار الموجود في الصور في الأسفل: <!DOCTYPE html> <html> <head> <title>Script-Tutorials: Default icons in jQuery Mobile</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" /> <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script> <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script> </head> <body> <div data-role="page" data-fullscreen="false"> <div data-role="header" data-position="fixed"> <a href="#" data-icon="back">Previous</a> <h1>jQuery Default Icon </h1><a href="#" data-icon="gear">Settings</a> </div> <div data-role="content"> <a href="#" data-role="button" data-icon="back">Back</a> <a href="#" data-role="button" data-icon="home">Home</a> <a href="#" data-role="button" data-icon="forward">Forward</a> </div> <div data-role="footer" data-position="fixed" data-id="rps"> <div data-role="navbar"> <ul> <li><a href="features.html" class="ui-btn-active ui-statepersist">Features</a> </li> <li><a href="supports.html">Supports</a> </li> <li><a href="contacts.html">Contacts</a> </li> </ul> </div> </div> </div> </body> </html> وضع أيقونات jQuery Mobile الافتراضية في أماكن مختلفة في الزر هذا هو السلوك الافتراضي لمكان الأيقونة على الأزرار، يمكننا تغيير مكان الأيقونة باستخدام خاصية data-iconpos=""‎ مع القيمة top، أو right، أو bottom وستكون الأيقونة في المكان الذي تخبرها بها، يمكننا أيضا استخدام القيمة notext لإبقاء الأيقونة على الزر وحذف النص، وهذا سيغير من حجم الزر ليكون أكبر بقليل من حجم الأيقونة نفسها ويمكن أن يكون مفيدا عندما تحتاج إلى وضع عدة أزرار على سطر واحد لشاشة صغيرة. مثال 39: استخدام الخاصية data-iconpos في تحديد مكان الأيقونة في الزر <!DOCTYPE html> <html> <head> <title>Script-Tutorials: Default icons in jQuery Mobile</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" /> <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script> <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script> </head> <body> <div data-role="page" data-fullscreen="false"> <div data-role="header" data-position="fixed"> <a href="#">Buy Me</a> <h1>Full Screen </h1><a href="#">Apply Now</a> </div> <div data-role="content"> <p>Use of data-iconpos Attribute in defining Icon placement in button</p> <a href="#" data-role="button" data-icon="back">Back</a> <a href="#" data-role="button" data-icon="home" data-iconpos="top">Home</a> <a href="#" data-role="button" data-icon="forward" data-iconpos="right">Forward</a> <a href="#" data-role="button" data-icon="gear" data-iconpos="bottom">Config</a> <a href="#" data-role="button" data-icon="info" data-iconpos="notext">information</a> </div> <div data-role="footer" data-position="fixed" data-id="rps"> <div data-role="navbar"> <ul> <li><a href="features.html" class="ui-btn-active ui-statepersist">Features</a> </li> <li><a href="supports.html">Supports</a> </li> <li><a href="contacts.html">Contacts</a> </li> </ul> </div> </div> </div> </body> </html> إنشاء أيقونات مخصصة ربما لاحظت أن جميع الأيقونات المتضمنة موجودة في أعلى دائرة أو قرص، وهذا سيساعد على إبراز الأيقونة وعملها على أي لون خلفية، يجب أن يناسب هذا القرص مساحة 18×18 بيكسل، وهذا معناه أنه عندما تصمم زر مخصص، ستحتاج إلى إضافة مساحة بعض البيكسلات حتى لا تظهر الأيقونة مقتطعة أو خارج مكانها عن وضع القرض. أنشئنا قرص الأيقونة وأضفنا الأيقونة باستخدام مقتطف شيفرة البرمجيةCSS: <style> .ui-icon-custom-cart-icon { background-image: url("godwins_customize_cart-icon.png"); } @media only screen and (-webkit-min-device-pixel-ratio: 2) { .ui-icon-custom-cart-icon { background-image: url("customised_cart-icon.png"); background-size: 18px 18px; } } </style> ثم أضفه إلى شيفرة HTML الخاص بنا كما هو موضح أدناه: <div data-role="content"> <a href="#" data-role="button" data-icon="custom-cart-icon">Customised Cart icon</a> </div> مثال 40: تطبيق زر مخصص على الزر استخدمنا الخاصية data-icon ومررنا لها قيمة مخصصة، تُستخدم القيمة custom-cart-icon لتوليد صف باسم ui-icon-custom-cart-icon: <!DOCTYPE html> <html> <head> <title>Script-Tutorials: Cutomized icons in jQuery Mobile</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" /> <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script> <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script> <style> .ui-icon-custom-cart-icon { background-image: url("godwins_customize_cart-icon.png"); } @media only screen and (-webkit-min-device-pixel-ratio: 2) { .ui-icon-custom-cart-icon { background-image: url("customised_cart-icon.png"); background-size: 18px 18px; } } </style> </head> <body> <div data-role="page" data-fullscreen="false"> <div data-role="header" data-position="fixed"> <a href="#" data-icon="back">Previous</a> <h1>Custom Icon </h1><a href="#" data-icon="gear">Settings</a> </div> <div data-role="content"> <a href="#" data-role="button" data-icon="custom-cart-icon">Customised Cart icon</a> </div> <div data-role="footer" data-position="fixed" data-id="rps"> <div data-role="navbar"> <ul> <li><a href="features.html" class="ui-btn-active ui-statepersist">Features</a> </li> <li><a href="supports.html">Supports</a> </li> <li><a href="contacts.html">Contacts</a> </li> </ul> </div> </div> </div> </body> </html> يُستخدم استعلام الوسائط (media query) للتحقق من دعم متصفح الهاتف للأيقونات عالية الدقة، إذا كان المتصفح يدعمهم، فستعمل شيفرة CSS الموجودة داخل media-query. الخاصية background-image تشير إلى ملف عالي الدقة. يجب أن تتناسب الصورة مع مساحة 18×18 بيكسل، فبدون تعيين هذه الخاصية، ستحاول الصور الأكبر التوسع وسيكون أغلبها مخفي مع إبقاء جزء صغير من الأيقونة المخصصة ظاهر. استخدام الأيقونات والأصناف على الرغم من أن CSS3 يساعد على تقليل حجم الملف، لاتزال بعض الأصول (assets) الثابتة تُستخدم أيضا، لذا جُمعوا معا للتقليل من عدد الملفات الذي يتم تحميلهم عند الحاجة. يستخدم القالب الحالة 5 ملفات صور ثابتة: ajax-loader.png—هذا هو المُحمل المتحرّك. icons-18-white.png—يحتوي على 22 أيقونة بيضاء. icons-18-black.png—يحتوي على 22 أيقونة سوداء. icons-36-white.png—يحتوي على 22 أيقونة بيضاء ذات دقة عالية. icons-36-black.png—يحتوي على 22 أيقونة سوداء ذات دقة عالية. الملف ajax-loader.png هو صور للمُحمّل الذي يظهر عند تحميل الصفحات عبر AJAX، أبعاد الصورة هي35×35 بيكسل وتُحمل عن طريق المتصفح عند تحميل الصفحة. ملفا icons-18-white.png وicons-18-black.png هي نقوش متحركة أفقيا بحجم 776×18 لكل منها، وتحتوي على 22 أيقونة أو صورة بحجم 18×18 بيكسل مفصولة بمساحة 18 بيكسل، أغلب الأيقونات في هذا الملف لا تأخذ مساحة 18×18 كاملة، وهذا لأن القرص الدائري يعمل عبر CSS كخلفية لمساعدة الأيقونات على البقاء ظاهرة على أي مكان تكون فيه. كل صورة لديها ما بين 2 و 4 بيكسل مساحة فارغة حول الحواف لإفساح المجال للقرص. ملفا icons-36-white.png و icons-36-black.png هي نقوش متحركة تحتوي على نفس الصور كما في الملفات الأولى، ولكن الفرق أنَّ الأيقونات هنا بحجم 36×36 بيكسل مع مساحة 36 بينهم لتستخدم في شاشات العرض عالية الدقة، مثال شاشات Retina™‎. تُحمل هذه الأيقونات عالية الدقة فقط على الأجهزة التي تدعمهم، لذلك لا تقلق حول بطء التحميل على الأجهزة التي لا تستخدمها، ويتم هذا عبر هذا المقتطف الذي يتحقق من توافق الأجهزة: @media only screen and(-webkit - min - device - pixel - ratio: 1.5), only screen and(min--moz - device - pixel - ratio: 1.5), only screen and(min - resolution: 240 dpi) {} إذا كان الجهاز لا يلبي متطلبات استعلام الوسائط، فسيتخطى الشيفرة البرمجية التي بداخله ولن تُحمّل. إضافة قوالب jQuery Mobile ونماذج ألوان إلى موقعك في jQuery Mobile، القالب (theme) هو تصميم مرئي موحد يُطبّق على الواجهة. من الناحية العملية، يحدد القالب كل شيء من الخطوط إلى إسقاط الظلال إلى الألوان. تماشيًا مع فكرة فصل التخطيط من اللون والنسيج (texture)، يمكن لقالب jQuery Mobile الحصول على عدة نماذج للألوان، فنماذج الألوان (Swatches) هي مجموعة من الأنماط المُعرَّفة التي يمكن أن تُطبَّق عند استخدام القالب. افتراضيًا، يوجد 5 نماذج للألوان متضمنة في jQuery Mobile، يمكنك تغيير النموذج الافتراضي المُطبَّق على صفحة كاملة بتضمين الخاصية data-theme مع قيمة النموذج الذي تريد تحميله، وعند تحميل الصفحة، جميع المكونات ما عدا الرأس ستحصل على مخطط ألوان ذلك النموذج. نموذج اللون (swatch) هو مفهوم اللون الموحد (unified color) الذي يحكم ألوان الخلفية والنص والظلال والأيقونة ...إلخ. قالب jQuery Mobile الافتراضي يتضمن 5 نماذج (تسمى a، و b، و c، و d و e) ويوفر كل نموذج تركيز بصري، فسيكون التركيز البصري أكثر وضوحًا مع النموذج a (عادةً نص أبيض على خلفية سوداء)، والنموذج d هو الأكثر ليونة. النموذج e يمثِّل حالة "الخطأ" (error)، وستكون في معظم الحالات النموذج c هو النموذج الافتراضي في jQuery Mobile، لكن من السهل اختيار نموذج مختلف باستخدام الخاصية data-theme، فيمكن تطبيق هذه الخاصية على أي عنصر وسيُطبَّق تلقائيًّا على العناصر الفرعية. ومع ذلك، تمت إضافة الخاصية data-theme="b"‎ إلى الشيفرة الأساسية اللازمة لإعداد الصفحة، وستغير هذه الخاصية النموذج المُطبّق على كامل الصفحة. إنتبه إلى أنَّه لن يُغيَّر النموذج للرأس والذيل، ويجب عليك لتغييرهما تضمين الخاصية data-theme بشكل منفصل. المثال 41: إضافة قوالب jQuery mobile ونماذج ألوان إلى الشيفرة الأساسية لإعداد صفحة <!DOCTYPE html> <html> <head> <title>Script-Tutorials: Swatches</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.css"> <script src="http://code.jquery.com/jquery-1.11.3.min.js"></script> <script src="http://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.js"></script> </head> <body> <div data-role="page" data-theme="b"> <div data-role="header"> <h1>Single Swatch</h1> </div> <div data-role="content"> <p>Look at the button!</p> <a href="#" data-role="button">I am a button</a> <ul data-role="listview" data-inset="true"> <li>List Item 1</li> <li>List Item 2</li> <li>List Item 3</li> </ul> </div> </div> </body> </html> المثال 42: إضافة نماذج ألوان مشتركة في jQuery mobile <!DOCTYPE html> <html> <head> <title>Script-Tutorials: Cutomized icons in jQuery Mobile</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" /> <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script> <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script> </head> <body> <section id="swatch-default" data-role="page"> <header data-role="header"> <h1>jQuery Mobile</h1> </header> <div class="content" data-role="content"> <h3>Default Swatch</h3> <ul data-role="listview"> <li><a href="#swatch-a">View swatch a</a> </li> <li><a href="#swatch-b">View swatch b</a> </li> <li><a href="#swatch-c">View swatch c</a> </li> <li><a href="#swatch-d">View swatch d</a> </li> <li><a href="#swatch-e">View swatch e</a> </li> </ul> <p>Some sample form elements and buttons:</p> <form action="formprocessor.php" method="post"> <div data-role="fieldcontain"> <label for="select-courses">Select Your Courses:</label> <select id="select-courses" name="select-courses" data-native-menu="false" multiple="multiple"> <option value="choose" data-placeholder="true">Choose...</option> <optgroup label="Microsoft Supports"> <option value="Word">Word</option> <option value="Powerpoint">Powerpoint</option> <option value="Excel">Excel</option> <option value="Access">Access</option> </optgroup> <optgroup label="Graphic Suite"> <option value="CorelDraw">CorelDraw</option> <option value="Adobe Photoshop" disabled="disabled">Adobe Photoshop</option> <option value="Photoshine">Photoshine</option> <option value="Paint">Paint</option> </optgroup> </select> </div> </form> <div data-role="controlgroup" data-type="horizontal"> <a href="#" data-role="button" data-icon="star">Yes</a> <a href="#" data-role="button" data-icon="alert">No</a> <a href="#" data-role="button" data-icon="home">Cancel</a> </div> </div> <footer data-role="footer"> <h1>Footer content</h1> </footer> <div data-role="footer" data-position="fixed" data-id="rps"> <div data-role="navbar"> <ul> <li><a href="#" class="ui-btn-active ui-statepersist">Features</a> </li> <li><a href="#">Supports</a> </li> <li><a href="#">Contacts</a> </li> </ul> </div> </div> </section> <section id="swatch-a" data-role="page" data-theme="a"> <header data-role="header"> <h1>jQuery Mobile</h1> </header> <div class="content" data-role="content"> <h3>Swatch A</h3> <ul data-role="listview"> <li><a href="#swatch-default">View default swatch</a> </li> <li><a href="#swatch-b">View swatch b</a> </li> <li><a href="#swatch-c">View swatch c</a> </li> <li><a href="#swatch-d">View swatch d</a> </li> <li><a href="#swatch-e">View swatch e</a> </li> </ul> <p>Some sample form elements and buttons:</p> <form action="formprocessor.php" method="post"> <div data-role="fieldcontain"> <label for="select-courses">Select Your Courses:</label> <select id="select-courses" name="select-courses" data-native-menu="false" multiple="multiple"> <option value="choose" data-placeholder="true">Choose...</option> <optgroup label="Microsoft Supports"> <option value="Word">Word</option> <option value="Powerpoint">Powerpoint</option> <option value="Excel">Excel</option> <option value="Access">Access</option> </optgroup> <optgroup label="Graphic Suite"> <option value="CorelDraw">CorelDraw</option> <option value="Adobe Photoshop" disabled="disabled">Adobe Photoshop</option> <option value="Photoshine">Photoshine</option> <option value="Paint">Paint</option> </optgroup> </select> </div> </form> <div data-role="controlgroup" data-type="horizontal"> <a href="#" data-role="button" data-icon="star">Yes</a> <a href="#" data-role="button" data-icon="alert">No</a> <a href="#" data-role="button" data-icon="home">Cancel</a> </div> </div> <footer data-role="footer"> <h1>Footer content</h1> </footer> <div data-role="footer" data-position="fixed" data-id="rps"> <div data-role="navbar"> <ul> <li><a href="#" class="ui-btn-active ui-statepersist">Features</a> </li> <li><a href="#">Supports</a> </li> <li><a href="#">Contacts</a> </li> </ul> </div> </div> </section> <section id="swatch-b" data-role="page" data-theme="b"> <header data-role="header"> <h1>jQuery Mobile</h1> </header> <div class="content" data-role="content"> <h3>Swatch B</h3> <ul data-role="listview"> <li><a href="#swatch-default">View default swatch</a> </li> <li><a href="#swatch-a">View swatch a</a> </li> <li><a href="#swatch-c">View swatch c</a> </li> <li><a href="#swatch-d">View swatch d</a> </li> <li><a href="#swatch-e">View swatch e</a> </li> </ul> <p>Some sample form elements and buttons:</p> <form action="formprocessor.php" method="post"> <div data-role="fieldcontain"> <label for="select-courses">Select Your Courses:</label> <select id="select-courses" name="select-courses" data-native-menu="false" multiple="multiple"> <option value="choose" data-placeholder="true">Choose...</option> <optgroup label="Microsoft Supports"> <option value="Word">Word</option> <option value="Powerpoint">Powerpoint</option> <option value="Excel">Excel</option> <option value="Access">Access</option> </optgroup> <optgroup label="Graphic Suite"> <option value="CorelDraw">CorelDraw</option> <option value="Adobe Photoshop" disabled="disabled">Adobe Photoshop</option> <option value="Photoshine">Photoshine</option> <option value="Paint">Paint</option> </optgroup> </select> </div> </form> <div data-role="controlgroup" data-type="horizontal"> <a href="#" data-role="button" data-icon="star">Yes</a> <a href="#" data-role="button" data-icon="alert">No</a> <a href="#" data-role="button" data-icon="home">Cancel</a> </div> </div> <footer data-role="footer"> <h1>Footer content</h1> </footer> <div data-role="footer" data-position="fixed" data-id="rps"> <div data-role="navbar"> <ul> <li><a href="#" class="ui-btn-active ui-statepersist">Features</a> </li> <li><a href="#">Supports</a> </li> <li><a href="#">Contacts</a> </li> </ul> </div> </div> </section> <section id="swatch-c" data-role="page" data-theme="c"> <header data-role="header"> <h1>jQuery Mobile</h1> </header> <div class="content" data-role="content"> <h3>Swatch C</h3> <ul data-role="listview"> <li><a href="#swatch-default">View default swatch</a> </li> <li><a href="#swatch-a">View swatch a</a> </li> <li><a href="#swatch-b">View swatch b</a> </li> <li><a href="#swatch-d">View swatch d</a> </li> <li><a href="#swatch-e">View swatch e</a> </li> </ul> <p>Some sample form elements and buttons:</p> <form action="formprocessor.php" method="post"> <div data-role="fieldcontain"> <label for="select-courses">Select Your Courses:</label> <select id="select-courses" name="select-courses" data-native-menu="false" multiple="multiple"> <option value="choose" data-placeholder="true">Choose...</option> <optgroup label="Microsoft Supports"> <option value="Word">Word</option> <option value="Powerpoint">Powerpoint</option> <option value="Excel">Excel</option> <option value="Access">Access</option> </optgroup> <optgroup label="Graphic Suite"> <option value="CorelDraw">CorelDraw</option> <option value="Adobe Photoshop" disabled="disabled">Adobe Photoshop</option> <option value="Photoshine">Photoshine</option> <option value="Paint">Paint</option> </optgroup> </select> </div> </form> <div data-role="controlgroup" data-type="horizontal"> <a href="#" data-role="button" data-icon="star">Yes</a> <a href="#" data-role="button" data-icon="alert">No</a> <a href="#" data-role="button" data-icon="home">Cancel</a> </div> </div> <footer data-role="footer"> <h1>Footer content</h1> </footer> <div data-role="footer" data-position="fixed" data-id="rps"> <div data-role="navbar"> <ul> <li><a href="#" class="ui-btn-active ui-statepersist">Features</a> </li> <li><a href="#">Supports</a> </li> <li><a href="#">Contacts</a> </li> </ul> </div> </div> </section> <section id="swatch-d" data-role="page" data-theme="d"> <header data-role="header"> <h1>jQuery Mobile</h1> </header> <div class="content" data-role="content"> <h3>Swatch D</h3> <ul data-role="listview"> <li><a href="#swatch-default">View default swatch</a> </li> <li><a href="#swatch-a">View swatch a</a> </li> <li><a href="#swatch-b">View swatch b</a> </li> <li><a href="#swatch-c">View swatch c</a> </li> <li><a href="#swatch-e">View swatch e</a> </li> </ul> <p>Some sample form elements and buttons:</p> <form action="formprocessor.php" method="post"> <div data-role="fieldcontain"> <label for="select-courses">Select Your Courses:</label> <select id="select-courses" name="select-courses" data-native-menu="false" multiple="multiple"> <option value="choose" data-placeholder="true">Choose...</option> <optgroup label="Microsoft Supports"> <option value="Word">Word</option> <option value="Powerpoint">Powerpoint</option> <option value="Excel">Excel</option> <option value="Access">Access</option> </optgroup> <optgroup label="Graphic Suite"> <option value="CorelDraw">CorelDraw</option> <option value="Adobe Photoshop" disabled="disabled">Adobe Photoshop</option> <option value="Photoshine">Photoshine</option> <option value="Paint">Paint</option> </optgroup> </select> </div> </form> <div data-role="controlgroup" data-type="horizontal"> <a href="#" data-role="button" data-icon="star">Yes</a> <a href="#" data-role="button" data-icon="alert">No</a> <a href="#" data-role="button" data-icon="home">Cancel</a> </div> </div> <footer data-role="footer"> <h1>Footer content</h1> </footer> <div data-role="footer" data-position="fixed" data-id="rps"> <div data-role="navbar"> <ul> <li><a href="#" class="ui-btn-active ui-statepersist">Features</a> </li> <li><a href="#">Supports</a> </li> <li><a href="#">Contacts</a> </li> </ul> </div> </div> </section> <section id="swatch-e" data-role="page" data-theme="e"> <header data-role="header"> <h1>jQuery Mobile</h1> </header> <div class="content" data-role="content"> <h3>Swatch E</h3> <ul data-role="listview"> <li><a href="#swatch-default">View default swatch</a> </li> <li><a href="#swatch-a">View swatch a</a> </li> <li><a href="#swatch-b">View swatch b</a> </li> <li><a href="#swatch-c">View swatch c</a> </li> <li><a href="#swatch-d">View swatch d</a> </li> </ul> <p>Some sample form elements and buttons:</p> <form action="formprocessor.php" method="post"> <div data-role="fieldcontain"> <label for="select-courses">Select Your Courses:</label> <select id="select-courses" name="select-courses" data-native-menu="false" multiple="multiple"> <option value="choose" data-placeholder="true">Choose...</option> <optgroup label="Microsoft Supports"> <option value="Word">Word</option> <option value="Powerpoint">Powerpoint</option> <option value="Excel">Excel</option> <option value="Access">Access</option> </optgroup> <optgroup label="Graphic Suite"> <option value="CorelDraw">CorelDraw</option> <option value="Adobe Photoshop" disabled="disabled">Adobe Photoshop</option> <option value="Photoshine">Photoshine</option> <option value="Paint">Paint</option> </optgroup> </select> </div> </form> <div data-role="controlgroup" data-type="horizontal"> <a href="#" data-role="button" data-icon="star">Yes</a> <a href="#" data-role="button" data-icon="alert">No</a> <a href="#" data-role="button" data-icon="home">Cancel</a> </div> </div> <footer data-role="footer"> <h1>Footer content</h1> </footer> <div data-role="footer" data-position="fixed" data-id="rps"> <div data-role="navbar"> <ul> <li><a href="#" class="ui-btn-active ui-statepersist">Features</a> </li> <li><a href="#">Supports</a> </li> <li><a href="#">Contacts</a> </li> </ul> </div> </div> </section> </body> </html> النموذج الافتراضية النموذج A القطعة B النموذج C النموذج D النموذج E وإليك بعض الصور لعنصر إدخال من نوع خيار متعدد بنماذج متعددة: خلط عدة نماذج مع بعضها بعضًا يمكنك خلط ومطابقة النماذج داخل الصفحة، مما يتيح لك السيطرة الدقيقة على مظهر التطبيق. المثال 43: خلط النماذج الافتراضية المشتركة في jQuery mobile <!DOCTYPE html> <html> <head> <title>Script-Tutorials: Cutomized icons in jQuery Mobile</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" /> <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script> <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script> </head> <body> <section id="swatch-mixed" data-role="page" data-theme="e"> <header data-role="header" data-theme="b"> <h1>jQuery Mobile</h1> </header> <div class="content" data-role="content"> <h3>Mixing Swatches</h3> <form action="formprocessor.php" method="post"> <div data-role="fieldcontain"> <label for="select-courses">Select Your Courses:</label> <select id="select-courses" name="select-courses" data-native-menu="false" multiple="multiple"> <option value="choose" data-placeholder="true">Choose...</option> <optgroup label="Microsoft Supports"> <option value="Word">Word</option> <option value="Powerpoint">Powerpoint</option> <option value="Excel">Excel</option> <option value="Access">Access</option> </optgroup> <optgroup label="Graphic Suite"> <option value="CorelDraw">CorelDraw</option> <option value="Adobe Photoshop" disabled="disabled">Adobe Photoshop</option> <option value="Photoshine">Photoshine</option> <option value="Paint">Paint</option> </optgroup> </select> </div> </form> <div data-role="controlgroup" data-type="horizontal"> <a href="#" data-role="button" data-icon="star">Yes</a> <a href="#" data-role="button" data-icon="alert">No</a> <a href="#" data-role="button" data-icon="home">Cancel</a> </div> </div> </div> <footer data-role="footer" data-theme="d"> <h1>Okeagu Godwin</h1> </footer> <div data-role="footer" data-position="fixed" data-id="rps" data-theme="d"> <div data-role="navbar"> <ul> <li><a href="#" class="ui-btn-active ui-statepersist">Features</a> </li> <li><a href="#">Supports</a> </li> <li><a href="#">Contacts</a> </li> </ul> </div> </div> </section> </body> </html> تحديد النموذج المراد تطبيقه على العناصر عن طريق الأصناف بدءًا من الجزء العلوي، يمكنك أن ترى أن كل من الصفحة وأقسام الرأس لا تستخدم الخاصية datatheme لذلك سيُستخدم القالب الافتراضي على هذه الأقسام. المثال 44: خلط النماذج الافتراضية المشتركة فيjQuery mobile بتحديد النموذج المطبَّق على على العناصر حسب قيمة خاصية الصنف <!DOCTYPE html> <html> <head> <title>Script-Tutorials: Swatches</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0-rc.1/jquery.mobile-1.1.0-rc.1.min.css" /> <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script> <script src="http://code.jquery.com/mobile/1.1.0-rc.1/jquery.mobile-1.1.0-rc.1.min.js"> </script> </head> <body> <div data-role="page"> <div data-role="header"> <h1>Class Swatch</h1> </div> <div data-role="content" class="ui-body-a"> <p>The body or content area is using class="ui-body-a"</p> <a href="#" data-role="button" class="ui-btn-up-e">class="ui-btn-up-e"</a> <ul data-role="listview" data-inset="true" class="ui-bar-d"> <li>This list</li> <li>is using</li> <li>class="ui-bar-d"</li> </ul> </div> </div> </body> </html> على الرغم من استخدام أصناف قليلة، إلا أنه يمكنك تخصيص كل جانب من أنماط jQuery Mobile عن طريق استبدال الأصناف كما يلي: ui-bar-(a-z) ui-body-(a-z) ui-btn-up-(a-z) ui-btn-down-(a-z) ui-btn-active ui-corner-all -ui-br ui-icon ui-icon-alt ui-overlay ui-shadow للإطلاع على كافة الأصناف التي يمكنك استخدامها، افتح ملف CSS غير المضغوط أو ملف CSS المُصغَّر الذي هو جزء من إطار jQuery Mobile وستجد تعليقات في هذا الملف وهو مفيد حقًا عندما تريد إنشاء أنماطك المخصصة. دعنا نلقي نظرة حول كيفية إنشاء أنماطنا الخاصة وتضمينها. التعديل على نموذج ألوان موجود تُعرّف نموذج ألوان القالب في jQuery Mobile عن طريق CSS، لذلك فهي سهلة التعديل لتناسب الاحتياجات الفردية الخاصة بك. تُقسم النماذج إلى أقسام في ورقة أنماط jQuery Mobile وهي واضحة. أفضل طريقة لتعديل القالب هي عن طريق إنشاء ورقة أنماط للأنماط المطلوبة ومن ثم تحميلها بعد تحميل ورقة أنماط jQuery Mobile، وهذا مفيد بشكل خاص إذا كنت تستخدم CDN لخدمة ورقة أنماط jQuery Mobile. تطبيق قالب مخصص الآن، أنت قادر على تخصيص أنماط jQuery Mobile باستخدام أصناف CSS، وحان الوقت الآن لتعديل الأنماط الافتراضية وتضمين الأنماط الخاصة بك. وللقيام بذلك ستحتاج إلى تعديل ملف CSS الموجود، أو إنشاء واحد خاص بك وإضافته إلى الصفحة. لأنني أعتقد في استخدام أساليب غير تدميرية عند تعلم شيء جديد، أنشأت ورقة أنماط CSS جديدة وأضفتها إلى صفحتنا. على سبيل المثال، لنفترض أننا نريد تغيير اللون الأصفر من النموذج E إلى الأخضر، يمكننا فعل ذلك بسهولة عن طريق تغيير بعض قواعد CSS. لاحظ أنني قمت بتضمين ورقة أنماط النموذج E بعد ورقة أنماط jQuery Mobile مما يضمن أن أنماطي ستحل محل الأنماط الافتراضية. مثال 45: تطبيق قالب مخصص <!DOCTYPE html> <html> <head> <title>Script-Tutorials: Cutomized icons in jQuery Mobile</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" /> <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script> <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script> <style> /* Change: #fceda7 to #a7fcaf #fadb4e to #5afa4e #f7c942 to #5cf742 #33ff33 to #9efaa2 #fe3 to #33ff33 #fcf0b5 to #b5fcb5 #e79952 to #52e760 #fbe26f to #76fb6f */ .ui-bar-e { border: 1px solid #5cf742; background: #5afa4e; background-image: -moz-linear-gradient(top, #a7fcaf, #5afa4e); background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, #a7fcaf), color-stop(1, #5afa4e)); -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#a7fcaf',EndColorStr='#5afa4e')"; } .ui-body-e { border: 1px solid #5cf742; background: #9efaa2; background-image: -moz-linear-gradient(top, #fff, #9efaa2); background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, #fff), color-stop(1, #9efaa2)); -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#ffffff',EndColorStr='#9efaa2')"; } .ui-btn-up-e { border: 1px solid #5cf742; background: #5afa4e; text-shadow: 0 1px 1px #33ff33; background-image: -moz-linear-gradient(top, #a7fcaf, #5afa4e); background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, #a7fcaf), color-stop(1, #5afa4e)); -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#a7fcaf',EndColorStr='#5afa4e')"; } .ui-btn-hover-e { border: 1px solid #52e760; background: #76fb6f; background-image: -moz-linear-gradient(top, #b5fcb5, #76fb6f); background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, #b5fcb5), color-stop(1, #76fb6f)); -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#b5fcb5',EndColorStr='#76fb6f')"; } .ui-btn-down-e { border: 1px solid #5cf742; background: #a7fcaf; background-image: -moz-linear-gradient(top, #5afa4e, #a7fcaf); background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, #5afa4e), color-stop(1, #a7fcaf)); -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#5afa4e',EndColorStr='#a7fcaf')"; } </style> </head> <body> <section id="swatch-e" data-role="page" data-theme="e"> <header data-role="header" data-theme="e"> <h1>jQuery Mobile</h1> </header> <div class="content" data-role="content"> <h3>Swatch E</h3> <ul data-role="listview"> <li><a href="#swatch-default">View default swatch</a> </li> <li><a href="#swatch-a">View swatch a</a> </li> <li><a href="#swatch-b">View swatch b</a> </li> <li><a href="#swatch-c">View swatch c</a> </li> <li><a href="#swatch-d">View swatch d</a> </li> </ul> <p>Some sample form elements and buttons:</p> <form action="formprocessor.php" method="post"> <div data-role="fieldcontain"> <label for="select-courses">Select Your Courses:</label> <select id="select-courses" name="select-courses" data-native-menu="false" multiple="multiple"> <option value="choose" data-placeholder="true">Choose...</option> <optgroup label="Microsoft Supports"> <option value="Word">Word</option> <option value="Powerpoint">Powerpoint</option> <option value="Excel">Excel</option> <option value="Access">Access</option> </optgroup> <optgroup label="Graphic Suite"> <option value="CorelDraw">CorelDraw</option> <option value="Adobe Photoshop" disabled="disabled">Adobe Photoshop</option> <option value="Photoshine">Photoshine</option> <option value="Paint">Paint</option> </optgroup> </select> </div> </form> <div data-role="controlgroup" data-type="horizontal"> <a href="#" data-role="button" data-icon="star">Yes</a> <a href="#" data-role="button" data-icon="alert">No</a> <a href="#" data-role="button" data-icon="home">Cancel</a> </div> </div> <footer data-role="footer"> <h1>Footer</h1> </footer> <div data-role="footer" data-position="fixed" data-id="rps"> <div data-role="navbar"> <ul> <li><a href="#" class="ui-btn-active ui-statepersist">Features</a> </li> <li><a href="#">Supports</a> </li> <li><a href="#">Contacts</a> </li> </ul> </div> </div> </section> </body> </html> إنشاء نموذج مخصص سيكون لديك خيارات مختلفة عندما يتعلق الأمر بإنشاء نموذج ألوان. يمكنك إما تغيير النموذج الموجود (وهذا ما فعلناه مسبقًا) أو بناء واحد جديد من الصفر، أو نسخ واحد والتعديل عليه وتغيير الإعدادات حسب تفضيلك. وهنالك خيار آخر وهو "إنشاء قالبك الخاص باستخدام ThemeRoller". لإنشاء نموذج خاصة بك، سننسخ نموذجًا من النماذج الموجودة ومن ثم نُعدِّل على الأنماط كما نريد. ستجد في الأسفل نموذجًا كاملًا نسخناه وغيّرناه إلى نموذج مخصص. مثال 46: نموذج كامل – نسخ a وتعديله ليتحول إلى النموذج f <style> .ui-bar-f { border: 1px solid #4a4a4a; background: #333333; color: #ffffff; font-weight: bold; text-shadow: 0 -1px 1px #000000; background-image: -webkit-gradient(linear, left top, left bottom, from( #014D88), to( #111)); /* Saf4+, Chrome */ background-image: -webkit-linear-gradient(#014D88, #111); /* Chrome 10+, Saf5.1+ */ background-image: -moz-linear-gradient(#014D88, #111); /* FF3.6 */ background-image: -ms-linear-gradient(#014D88, #111); /* IE10 */ background-image: -o-linear-gradient(#014D88, #111); /* Opera 11.10+ */ background-image: linear-gradient(#014D88, #111); } .ui-bar-f, .ui-bar-f input, .ui-bar-f select, .ui-bar-f textarea, .ui-bar-f button { font-family: Helvetica, Arial, sans-serif; } .ui-bar-f .ui-link-inherit { color: #fff; } .ui-bar-f .ui-link { color: #F7E065; font-weight: bold; } .ui-bar-f .ui-link:hover { color: #FFFF7F; } .ui-bar-f .ui-link:active { color: #FFFF7F; } .ui-bar-f .ui-link:visited { color: #FFFF7F; } .ui-body-f, .ui-dialog.ui-overlay-f { border: 1px solid #3f3f3f; background: #444444; color: #fff; text-shadow: 0 1px 0 #000; font-weight: normal; background-image: -webkit-gradient(linear, left top, left bottom, from( #0C8DD2), to( #014D88)); /* Saf4+, Chrome */ background-image: -webkit-linear-gradient(#0C8DD2, #014D88); /* Chrome 10+, Saf5.1+ */ background-image: -moz-linear-gradient(#0C8DD2, #014D88); /* FF3.6 */ background-image: -ms-linear-gradient(#0C8DD2, #014D88/); /* IE10 */ background-image: -o-linear-gradient(#0C8DD2, #014D88); /* Opera 11.10+ */ background-image: linear-gradient(#0C8DD2, #014D88); } .ui-body-f, .ui-body-f input, .ui-body-f select, .ui-body-f textarea, .ui-body-f button { font-family: Helvetica, Arial, sans-serif; } .ui-body-f .ui-link-inherit { color: #fff; } .ui-body-f .ui-link { color: #FFFF7F; font-weight: bold; } .ui-body-f .ui-link:hover { color: #FFFF7F; } .ui-body-f .ui-link:active { color: #FFFF7F; } .ui-body-f .ui-link:visited { color: #FFFF7F; } .ui-btn-up-f { border: 1px solid #222; background: #065BDB; font-weight: bold; color: #fff; text-shadow: 0 -1px 1px #000; background-image: -webkit-gradient(linear, left top, left bottom, from( #1065E4), to( #065BDB)); /* Saf4+, Chrome */ background-image: -webkit-linear-gradient(#1065E4, #065BDB); /* Chrome 10+, Saf5.1+ */ background-image: -moz-linear-gradient(#1065E4, #065BDB); /* FF3.6 */ background-image: -ms-linear-gradient(#1065E4, #065BDB); /* IE10 */ background-image: -o-linear-gradient(#1065E4, #065BDB); /* Opera 11.10+ */ background-image: linear-gradient(#1065E4, #065BDB); } .ui-btn-up-f a.ui-link-inherit { color: #fff/; } .ui-btn-hover-f { border: 1px solid 000; background: #444444; font-weight: bold; color: #fff; text-shadow: 0 -1px 1px #000; background-image: -webkit-gradient(linear, left top, left bottom, from( #1A6FEF), to( #1065E4)); /* Saf4+, Chrome */ background-image: -webkit-linear-gradient(#1A6FEF, #1065E4); /* Chrome 10+, Saf5.1+ */ background-image: -moz-linear-gradient(#1A6FEF, #1065E4); /* FF3.6 */ background-image: -ms-linear-gradient(#1A6FEF, #1065E4); /* IE10 */ background-image: -o-linear-gradient(#1A6FEF, #1065E4); /* Opera 11.10+ */ background-image: linear-gradient(#1A6FEF, #1065E4); } .ui-btn-hover-f a.ui-link-inherit { color: #fff; } .ui-btn-down-f { border: 1px solid #014D88; background: #012E50; font-weight: bold; color: #fff; text-shadow: 0 -1px 1px #000; background-image: -webkit-gradient(linear, left top, left bottom, from( #013B66), to( #0261A9)); /* Saf4+, Chrome */ background-image: -webkit-linear-gradient(#013B66, #0261A9/); /* Chrome 10+, Saf5.1+ */ background-image: -moz-linear-gradient(#013B66, #0261A9); /* FF3.6 */ background-image: -ms-linear-gradient(#013B66, #0261A9); /* IE10 */ background-image: -o-linear-gradient(#013B66, #0261A); /* Opera 11.10+ */ background-image: linear-gradient(#013B66, #0261A9); } .ui-btn-down-f a.ui-link-inherit { color: #fff; } .ui-btn-up-f, .ui-btn-hover-f, .ui-btn-down-f { font-family: Helvetica, Arial, sans-serif; text-decoration: none; } </style> نسخنا وعدلنا على النموذج a وأنشأنا منه النموذج f. أسرع طريقة لبدء التعديلات هو عمل بحث واستبدال (search-and-replace) على كامل الملف لـ ‎-a واستبدالها بخط فاصل (-) مع حرف لاسم النموذج. عند إجراء بحث واستبدال، تأكد من عدم استبدال ‎-o أو ‎-m أو ‎-w أو ‎-g أو ‎-i لأنه إما ستخرّب النمط أو ستلغي دعمه للمتصفحات الاخرى. القالب f هو شيفرة HTML معاينة في متصفح هاتف. المثال 47: قالب f المعدل في إعدادات شيفرة HTML القياسية <!DOCTYPE html> <html> <head> <title>Script-Tutorials: Cutomized icons in jQuery Mobile</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" /> <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script> <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script> <style> .ui-bar-f { border: 1px solid #4a4a4a; background: #333333; color: #ffffff; font-weight: bold; text-shadow: 0 -1px 1px #000000; background-image: -webkit-gradient(linear, left top, left bottom, from( #014D88), to( #111)); /* Saf4+, Chrome */ background-image: -webkit-linear-gradient(#014D88, #111); /* Chrome 10+, Saf5.1+ */ background-image: -moz-linear-gradient(#014D88, #111); /* FF3.6 */ background-image: -ms-linear-gradient(#014D88, #111); /* IE10 */ background-image: -o-linear-gradient(#014D88, #111); /* Opera 11.10+ */ background-image: linear-gradient(#014D88, #111); } .ui-bar-f, .ui-bar-f input, .ui-bar-f select, .ui-bar-f textarea, .ui-bar-f button { font-family: Helvetica, Arial, sans-serif; } .ui-bar-f .ui-link-inherit { color: #fff; } .ui-bar-f .ui-link { color: #F7E065; font-weight: bold; } .ui-bar-f .ui-link:hover { color: #FFFF7F; } .ui-bar-f .ui-link:active { color: #FFFF7F; } .ui-bar-f .ui-link:visited { color: #FFFF7F; } .ui-body-f, .ui-dialog.ui-overlay-f { border: 1px solid #3f3f3f; background: #444444; color: #fff; text-shadow: 0 1px 0 #000; font-weight: normal; background-image: -webkit-gradient(linear, left top, left bottom, from( #0C8DD2), to( #014D88)); /* Saf4+, Chrome */ background-image: -webkit-linear-gradient(#0C8DD2, #014D88); /* Chrome 10+, Saf5.1+ */ background-image: -moz-linear-gradient(#0C8DD2, #014D88); /* FF3.6 */ background-image: -ms-linear-gradient(#0C8DD2, #014D88/); /* IE10 */ background-image: -o-linear-gradient(#0C8DD2, #014D88); /* Opera 11.10+ */ background-image: linear-gradient(#0C8DD2, #014D88); } .ui-body-f, .ui-body-f input, .ui-body-f select, .ui-body-f textarea, .ui-body-f button { font-family: Helvetica, Arial, sans-serif; } .ui-body-f .ui-link-inherit { color: #fff; } .ui-body-f .ui-link { color: #FFFF7F; font-weight: bold; } .ui-body-f .ui-link:hover { color: #FFFF7F; } .ui-body-f .ui-link:active { color: #FFFF7F; } .ui-body-f .ui-link:visited { color: #FFFF7F; } .ui-btn-up-f { border: 1px solid #222; background: #065BDB; font-weight: bold; color: #fff; text-shadow: 0 -1px 1px #000; background-image: -webkit-gradient(linear, left top, left bottom, from( #1065E4), to( #065BDB)); /* Saf4+, Chrome */ background-image: -webkit-linear-gradient(#1065E4, #065BDB); /* Chrome 10+, Saf5.1+ */ background-image: -moz-linear-gradient(#1065E4, #065BDB); /* FF3.6 */ background-image: -ms-linear-gradient(#1065E4, #065BDB); /* IE10 */ background-image: -o-linear-gradient(#1065E4, #065BDB); /* Opera 11.10+ */ background-image: linear-gradient(#1065E4, #065BDB); } .ui-btn-up-f a.ui-link-inherit { color: #fff/; } .ui-btn-hover-f { border: 1px solid 000; background: #444444; font-weight: bold; color: #fff; text-shadow: 0 -1px 1px #000; background-image: -webkit-gradient(linear, left top, left bottom, from( #1A6FEF), to( #1065E4)); /* Saf4+, Chrome */ background-image: -webkit-linear-gradient(#1A6FEF, #1065E4); /* Chrome 10+, Saf5.1+ */ background-image: -moz-linear-gradient(#1A6FEF, #1065E4); /* FF3.6 */ background-image: -ms-linear-gradient(#1A6FEF, #1065E4); /* IE10 */ background-image: -o-linear-gradient(#1A6FEF, #1065E4); /* Opera 11.10+ */ background-image: linear-gradient(#1A6FEF, #1065E4); } .ui-btn-hover-f a.ui-link-inherit { color: #fff; } .ui-btn-down-f { border: 1px solid #014D88; background: #012E50; font-weight: bold; color: #fff; text-shadow: 0 -1px 1px #000; background-image: -webkit-gradient(linear, left top, left bottom, from( #013B66), to( #0261A9)); /* Saf4+, Chrome */ background-image: -webkit-linear-gradient(#013B66, #0261A9/); /* Chrome 10+, Saf5.1+ */ background-image: -moz-linear-gradient(#013B66, #0261A9); /* FF3.6 */ background-image: -ms-linear-gradient(#013B66, #0261A9); /* IE10 */ background-image: -o-linear-gradient(#013B66, #0261A); /* Opera 11.10+ */ background-image: linear-gradient(#013B66, #0261A9); } .ui-btn-down-f a.ui-link-inherit { color: #fff; } .ui-btn-up-f, .ui-btn-hover-f, .ui-btn-down-f { font-family: Helvetica, Arial, sans-serif; text-decoration: none; } </style> </head> <body> <div data-role="page" data-theme="f"> <div data-role="header" data-theme="f"> <h1>Custom Styles</h1> </div> <div data-role="content"> <div data-role="collapsible" data-collapsed="false" data-content-theme="f"> <h3>Different Swatch</h3> <p> This collapsed content area uses a different style for the collapsed content than the rest of the page. </p> <a href="#" data-role="button" data-theme="f"> We just create an "F theme" of blue colour </a> </div> </div> <div data-role="footer" data-theme="f"> <h1>Script-Tutorials.com</h1> </div> </div> </body> </html> عناصر قالب الموقع لقد تعلمت للتو أنه يمكنك استخدام الأصناف لتغيير جوانب مختلفة من قالب موقعك، لكن توجد خيارات إضافية يمكنك استخدامها عند تغيير قالب للمكونات الفردية. تملك بعض المكونات إعدادات افتراضية يجب عليك معرفتها. الأزرار تستخدم الأزرار تلقائيًا نماذج الألوان المرتبطة بالحاوية الرئيسية، فإذا وضعت الزر في كتلة حاوية تستخدم النموذج b، فإن الزر المحتوى فيها سيستخدم النموذج b أيضًا. يمكنك تغيير هذا باستخدام الخاصية data-theme على الزر مباشرةً لتغيير النموذج الذي يستخدمه. يُظهر لك هذا المقتطف في سطر واحد كيفية تغيير قالب الزر باستخدام وفق ما ذكرنا آنقًا: <a href="#" data-role="button" data-theme="e"></a> مثال 48: استخدام قالب jQuery في مكونات موقع الزر <!DOCTYPE html> <html> <head> <title>Script-Tutorials: Themeing Components</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0-rc.1/jquery.mobile-1.1.0-rc.1.min.css" /> <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script> <script src="http://code.jquery.com/mobile/1.1.0-rc.1/jquery.mobile-1.1.0-rc.1.min.js"> </script> </head> <body> <div data-role="page"> <div data-role="header"> <h1>Themeing button </h1> </div> <div data-role="content"> <a href="#" data-role="button" data-theme="e">Theme E in button</a> </div> </div> </body> </html> الأشرطة (bars) تتضمن مكونات الأشرطة أقسام رأس وذيل الصفحة، إذ تستخدم النموذج الافتراضي لكن يمكن تغييره لاستخدام أي نموذج آخر تفضله عن طريق إضافة الخاصية data-theme. المقتطف المتكون من سطر واحد التالي يظهر لك استخدام عنصر div لإنشاء قسم الرأس الذي يستخدم الخاصية data-theme لتغيير النموذج المطبق عليه. <div data-role="header" data-theme="e"><h1>Using the e swatch</h1></div> المثال 49: استخدام قالب jQuery في مكونات أشرطة الموقع <!DOCTYPE html> <html> <head> <title>Script-Tutorials: Themeing Components</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0-rc.1/jquery.mobile-1.1.0-rc.1.min.css" /> <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script> <script src="http://code.jquery.com/mobile/1.1.0-rc.1/jquery.mobile-1.1.0-rc.1.min.js"> </script> </head> <body> <div data-role="page"> <div data-role="header" data-theme="e"> <h1>Using the e swatch</h1> </div> </div> </body> </html> كتل المحتوى يمكن أن يكون تغيير قالب محتوى الكتلة صعب قليلا، فـ jQuery يفترض أنك لا تطبق الخاصية data-theme مباشرةً على قيم المحتوى لصفحتك، وذلك لأن قسم المحتوى قد لا يأخذ كامل المساحة المرئية في الصفحة. عند حدوث هذا، ستُقطع الخلفية فجأة وستبدو الصفحة مكسورة. بدلًا من ذلك، يجب عليك تطبيق النموذج الذي تريد استخدامه عن طريق استخدام الخاصية data على العنصر الذي يحتوي الخاصية data-role="page"‎. يمكن لكتل المحتوى أن تتقبل خاصية قالب أخرى وهي data-content-theme، التي ستطبق على المحتوى الذي بداخل الحاويات القابلة للطي، ويمكن أن تطبق أيضا على العنصر الذي يحتوي الخاصية data-role="page"‎ وستتوارثه عناصره الفرعية. المثال 50: استخدام قالب jQuery في مكون كتل محتوى الموقع <!DOCTYPE html> <html> <head> <title>Script-Tutorials: Themeing Components</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0-rc.1/jquery.mobile-1.1.0-rc.1.min.css" /> <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script> <script src="http://code.jquery.com/mobile/1.1.0-rc.1/jquery.mobile-1.1.0-rc.1.min.js"> </script> </head> <body> <div data-role="page" data-theme="b"> <div data-role="header"> <h1>Custom Styles</h1> </div> <div data-role="content"> <div data-role="collapsible" data-collapsed="false" data-content-theme="e"> <h3>Different Swatch</h3> <p> This collapsed content area uses a different style for the collapsed content than the rest of the page. </p> </div> </div> </div> </body> </html> عند استخدام الخاصيتين data-theme و data-content-theme على عنصر، يطغى نموذج الألوان المستخدم في الخاصية data-content-theme عادةً على النموذج المستخدم في الخاصية datatheme وهذا يفسر لماذا ترى فقط النموذج الموجود في data-content-theme عند محاولتك لاستخدام الخاصيتين في حاوية الصفحة. ترجمة -وبتصرّف- للمقال jQuery Mobile Lesson 5 لصاحبه Andrew اقرأ أيضًا الدرس التالي: إنشاء القوائم وتنسيقها وإنشاء نماذج البحث وتسجيل الدخول الدرس السابق: ربط صفحات خارجية وتنظيم المحتوى بنظام الشبكة وبناء محتوى قابل للطي
  7. إذا كنت مثلي، ترغب في إعادة تصميم موقعك كل سنة أو سنتين، فلقد قمتُ بإعادة تصميم موقعي للتو ليعكس التغييرات على الخدمات التي أقدمها ونوع الكتابة التي أكتبها. لكن لن تحصل على مال عند إعادة تصميم موقعك، لذلك سترغب بجعل العملية أسهل وأسرع ما يمكن. في هذا المقال، سأريك تقنية بسيطة يمكنك إتباعها باستخدام إضافتين تابعتين لنا (Snapshot Pro و Cloner). سنستخدم إضافة Cloner كثيرًا، لكن إضافة Snapshot Pro مهمة أيضًا، ستعمل هذه التقنية إذا كنت تشغّل WordPress Multisite مع موقعك كواحد من المواقع (ربما الموقع الرئيسي) في الشبكة. سأوضح لك كيف يمكنك استخدام Cloner لإنشاء نسخة من موقعك القديم، ومن ثم العمل على هذه النسخة لتطوير وتجربة موقعك الجديد، ثم ستستخدم Cloner مجددًا لنقل ما فعلته في الموقع القديم. يجب عليك أيضًا استخدام Snapshot Pro لإنشاء النسخ الاحتياطيّة واستيراد البيانات أو الملفات التي تحتاج إليها. الشروع في العمل قبل البدء، ستحتاج إلى بعض الأشياء: شبكة Multisite (متعددة المواقع) تشّغل موقعك حيث أنك مشرف المواقع عليها. إضافة Cloner مثبّتة ومفعّلة. إضافة Snapshot Pro مثبّتة ومفعّلة. لن تحتاج إلى كتابة أي شيفرة برمجية في هذا المقال، لذلك لن تحتاج إلى محرر شيفرات برمجيّة، وصول FTP أو أي شيء مثل هذا. نسخ موقعك القديم الخطوة الأولى هي إنشاء نسخة من موقعك القديم، ومن ثم يمكنك العمل على هذه النسخة، والتبديل عندما تكون النسخة الجديدة جاهزة. أنصح دائمًا بإجراء الجزء الأكبر من أعمال إعادة تطوير على نسخة محلية من موقعك، لذلك قد يكون لديك بالفعل ثيم أو/و إضافات التي طوّرتها أو التخصيصات التي ترغب في رفعها، هذه التقنية تعني أنه يمكنك رفع هذه وتجربة عمل كل شيء في الخادم عن بعد قبل تطبيق التغييرات على الموقع الحي، وربما لديك الكثير من المحتوى الذي لم تنسخه في الموقع المحلي الذي تطوّره، بالإضافة إلى القدرة على التجربة في نسخة من موقعك على شبكتك يعني التأكد من العمل مع جميع البيانات من موقعك الرئيسي. في شبكة Multisite، اذهب إلى Network Admin‎‏ > Sites وستجد العديد من المواقع في شبكتك: الآن، مرر المؤشر على الموقع الذي تريد نسخه، سترى 4 خيارات Edit، Dashboard، Visit و Clone، اضغط على Clone. سيأخذك هذا إلى شاشة Clone Site: ستحتاج هنا إلى تحديد بعض الخيارات لنسخ موقعك: إنشاء موقع جديد/استبدال الموقع الحالي: ترغب في إنشاء موقع جديد لذلك اختر هذا الخيار، واكتب slug لموقعك الجديد. عنوان الموقع: يمكنك اختيار استخدام نفس العنوان القديم كموقعك الجديد أو إنشاء واحد جديد، ولتجنب الإرباك، أُعْطيه دائما اسم حتى أعرف أنه مجرد نسخة، فإذا كان اسم موقعي الأصلي هو Rachel McCollin، فسأدعو الموقع الجديد RM Dev Site، وحاول استخدام عنوان له نفس طول الأصلي بحيث يتلاءم في الرأس (header) بالطريقة نفسها. إمكانية رؤيته من محركات البحث: اختر خيار تثبيط المحركات البحث من فهرسة موقعك، فلا تريد أن يعثر الناس على موقعك الجاري تطويره بدلا من الذهاب إلى النسخة الحيّة من موقعك. خيارات متقدمة: إذا كنت تستنسخ الموقع الرئيسي، يمكنك اختيار جداول قاعدة البيانات للشبكة بدلا من الموقع، ولن ينسخ محتواها. في النهاية، اضغط على زر Clone Site لإنشاء الموقع الجديد، اجلس وانتظر حتى يعمل Cloner سحره، وسيخبرك Cloner بتقدم النسخ: تستغرق الوسائط المتعدّدة بعض الوقت، لذلك إذا كان يحتوي موقعك على الكثير من الصور، اذهب واشرب قهوة في الوقت الذي تنتظر فيها Cloner لإنشاء النسخة، وبما أن موقعي كبير فسأقوم بذلك وأنا أكتب. بعد انتهاء Cloner، ستنّقل إلى لوحة التحكم لنسخة موقعك: إعادة تطوير موقعك لا يمكنني إعطاءك الكثير من التوجيهات في الخطوة التالية، يمكنك إما رفع قوالب أو إضافات جربتها أو طوّرتها محليًا، أو يمكنك تجربة قوالب خارجية على نسخة موقعك. تأكد من أداء موقعك، حيث يمكنك تجربة الموقعين باستخدام Hummingbird للتأكد من أن موقع الجديد سريع على الخادم. بمجرد أن ترضى عن أداء الموقع الجديد، حان الوقت لنقله إلى موقعك الأصلي. عمل نسخ احتياطية لكن انتظر، قبل أن تتحمّس كثيرًا، دعونا ننتظر للحظة حتى نقوم بعمل نسخة احتياطيّة. في شاشات شبكة المدير، اذهب إلى Snapshot‏ >Snapshots وأنشئ لقطتين جديدتين: واحدة للموقع الأصلي وواحدة للموقع الذي طوّرته. إذا تمت إضافة أي محتوى أو رفع جديد إلى موقعك الأصلي في الوقت الذي تجرّب فيه الموقع الذي تطّوّره، ستحتاج إلى عمل لقطة جديدة للموقع الأصلي لاستيراد البيانات بعد نسخ الموقع المطوّر، اعمل نسخة احتياطية بالملفات والجداول التي تحتاج إلى استيرادها فقط. إذا لم تتم إضافة أي محتوى أو رفع جديد فلن تحتاج إلى فعل هذا، لكن يجب عليك إنشاء نسخة احتياطيّة للاحتياط. ملاحظة: أوصي باستخدام هذه التقنية لتجربة الشيفرة البرمجيّة التي تتطلّب وقتًا لإنشاءها في الموقع التطوير المحلي، وهذا يعني أنك ستنشئ النسخة الثانية في وقت ليس ببعيد من النسخة الأصلية ولم يتغير المحتوى والملفات في الموقع، سأخبرك ماذا تفعل إذا لم تكن هذه حالتك في آخر هذا المقال لكن يمكنك أن تعقد الأمور وهي خطيرة، لذلك لا أنصح بها. حصلّت على لقطاتك؟ جيّد، لنستنسخ. نسخ الموقع المُطوَّر حان الآن وقت نسخ موقعك الجديد المعاد تصميمه إلى موقعك الجديد، في شبكة المدير اذهب إلى شاشة Sites ومرر المؤشر على الموقع الجديد الذي تعمل عليه ثم اضغط على خيار Clone. ستجد نفسك في شاشة Clone Site مجددًا لكن ستختلف الخيارات التي ستختارها: إنشاء موقع جديد/استبدال الموقع القديم: اختر Replace existing site واترك الحقل فارغ للنسخ إلى الموقع الرئيسي إذا كان هذا ما تفعله، أو اكتب slug للموقع إذا لم يكن هذا موقعك الرئيسي. عنوان الموقع: اختر Overwrite blog title واكتب اسم الأصلي للمدونة. إمكانية رؤية محركات البحث: لا تختر خيار تثبيط محركات البحث من فهرسة موقعك، فأنت تريد بالتأكيد أن يتمكن الأشخاص من العثور على موقعك مباشرةً. خيارات متقدّمة: لن تطبّق هذه لأنك لم تستنسخ الموقع الرئيسي هذه المرّة. بمجرد انتهاءك من هذا، اضغط على Clone Site واذهب مرة أخرى واعمل قهوة مجددًا. استرد المحتوى إذا كنت بحاجة إلى ذلك إذا تغيّر محتوى موّقعك أثناء إجراء إعادة تصميم أو عند رفع أي ملفات وسائط متعدّدة جديدة فستحتاج إلى استيراد هذه إلى نسخة الحيّة الجديدة من موقع باستخدام اللقطة التي أنشأناها قبل نسخ الموقع المطوّر. في شاشة مدير الشبكة، اذهب إلى Snapshot > ‏Snapshots وابحث عن اللقطة التي أنشأتها من موقعك الأصلي (وليس لقطة موقع المطوّر). تسمى لقطتي بـ Pre-cloning snapshot: مرر المؤشر فوق النقاط الثلاثة على يمين اللقطة وانقر على Restore، وسيسترد Snapshot الملفات و/أو الجداول مع اللقطة. ملاحظة: إذا غيّرت أية إعدادات أثناء قيامك بعمل إعادة التطوير، ستحتاج إلى تعديل هذا يدوّيا، لا تسترد اللقطة لجدول wp-options وإلا سيلغي التغييرات على الثيم وإعدادات الإضافات عند إعادة تصميم موقعك. تجربة موقعك في النهاية، جرّب موقعك، تأكد من عمل جميع الروابط، تحميل الوسائط المتعددة بشكل صحيح وأن كل شيء يعمل جيّدًا. عندما تكون سعيدًا بموقعك الجديد، احذف الموقع المُطوَّر، فلا تريد تشويش الشبكة أو الارتباك، اذهب إلى شاشة Sites في شاشة شبكة المدير واضغط على Delete لذلك الموقع. سرّع إعادة تصميم موقعك باستخدام Cloner و Snapshot هذه التقنيّة ستجعل عملية إعادة تصميم موقعك سريعة وسهّلة، وهي مفيدة عند تجربة قوالب من مصدر خارجي أو إضافات يمكنك تثبيتها على الموقع الذي تطوّره، أو عندما تمتلك الشيفرة البرمجية التي جربتها في النسخة المحليّة عند تطوير موقعك وتريد اختباره في بيئة الموقع الحيّة. إذا كانت التغييرات التي تجريها على موقعك مهمة، فقد تفضّل استخدام موقع تجريبي لتجربة الأشياء قبل كتابتها على موقعك الأصلي، لكن إذا أردت تعديل القوالب أو تغيير إعدادات الإضافة، على سبيل المثال، فهذه طريقة سريعة وسهلة للقيام بذلك. ترجمة -وبتصرّف- للمقال How to Make a Multisite Redesign Pain-Free with Cloner and Snapshot لصاحبه Rachel McCollin
  8. في درسنا الرابع من هذه السلسلة، سنتابع الحديث حول الخاصية data-‎، وربط الصفحات الخارجية، واستخدام نظام الشبكة (grid system)، وبناء محتوى قابل للطي. بالإضافة إلى ذلك، ستتعلم كيف تنشئ تذييل ورأس وشريط تنقل ...إلخ. وكل ذلك مدعوم بأجزاء من شيفرات برمجية عملية. هذا الدرس جزء من سلسلة دروس تشرح jQuery Mobile: الدرس الأول: البداية، بناء وتقديم محتوى الدرس الثاني: التضمين، تهيئة الصفحة، التنقل بين الصفحات وأحداث التحميل الدرس الثالث: اتجاه الصفحة وأحداثها الدرس الرابع: ربط صفحات خارجية وتنظيم المحتوى بنظام الشبكة وبناء محتوى قابل للطي الدرس الخامس: الأيقونات والأزرار وإنشاء تنسيقات مخصصة الدرس السادس: إنشاء القوائم وتنسيقها وإنشاء نماذج البحث وتسجيل الدخول الصفحات الخارجية يتعامل jQuery Mobile مع الصفحات الخارجية أيضًا. فإذا ربطت صفحة منفصلة بدلًا من مُعرِّف عنصر data-role="page"‎ داخل المستند الحالي، سيجري jQuery Mobile إجراء جلب غير متزامن (asynchronous fetch) للصفحة المطلوبة ويدمجها في الصفحة الحالية ليسمح لها بتشغيل دوال إدارة الصفحة. لإضافة صفحة خارجية إلى الشيفرة البرمجية السابقة، أنشئ ملفًا باسمexpage.html وضمّن الشيفرة الآتية وغيّر الرابط في شيفرة الصفحة الثالثة والذي هو: <p><a href="#page1" data-role="button">Go back to First Page</a></p> إلى: <p><a href="expage.html" data-role="button">Go to external Page</a></p> مثال 22: ربط صفحة خارجية <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> </head> <body> <p>This content will be ignored.</p> <!-- Begin Page 4 --> <section id="page4" data-role="page"> <header data-role="header"> <h1>jQuery Mobile</h1> </header> <div class="content" data-role="content"> <p>External Page!</p> <p><a href="#page1" data-role="button">Go to First Page</a>.</p> </div> <footer data-role="footer"> <h1>footer</h1> </footer> </section> <!-- End Page 4--> <h3>This content will be ignored as well.</h3> </body> </html> عند معاينة هذا السكربت، سترى الصورة الأولى؛ ولكن عند الانتقال من الصفحة السابقة للسكربت السابق، ستظهر لك الصورة الثانية. تجاوز جلب الصفحة غير المتزامن ستحتاج في بعض الأحيان إلى تحميل الصفحة بشكل طبيعي بدلًا من جعل jQuery Mobile يجلبه بشكل غير متزامن ويُضمّنه إلى DOM الحالي. يمكنك تجاوز تحميل AJAX بطريقتين: تحديد الخاصية الهدف على الرابط (مثل "‎_blank") أو بتحديد الخاصية rel="external"‎ على الرابط. رصف المحتوى في شبكة الشبكة (grid) هي أداة لتنظيم الكائنات، ويستخدم jQuery Mobile النظام الشبكي لمساعدتك في رصف المحتوى؛ هذا النظام مفيد لأنه يساعدك على إنشاء صفحات متجاوبة مع عدة أجهزة وبذلك لست يأخذ هذا النظام على عاتقه تخمين كيفية عرض الصفحة على الأجهزة ذات الأحجام المختلفة بالشكل الذي خططت له. يسمح لك النظام الشبكي في jQuery Mobile بإنشاء أعمدة متساوية العرض. ولتطبيق نظام الشبكة (grid) على المحتوى، ستحتاج إلى إضافة صنف إلى الحاوية التي تريد استخدام الشبكة (grid) فيها، وصنف ثانوي إلى العناصر داخل الحاوية. أصناف حاوية الشبكة هي: ui-grid-a: تنشئ شبكة من عمودين. ui-grid-b: تنشئ شبكة من 3 أعمدة. ui-grid-c: تنشئ شبكة من 4 أعمدة. ui-grid-d: تنشئ شبكة من 5 أعمدة. أصناف المحتوى هي: ui-block-a: تُستخدم على الكتلة الأولى. ui-block-b: تُستخدم على الكتلة الثانية. ui-block-c: تُستخدم على الكتلة الثالثة. ui-block-d: تُستخدم على الكتلة الرابعة. ui-block-e: تُستخدم على الكتلة الخامسة. عند استخدام شبكة على حاوية ذات عناصر بمحتوى أعرض من دقة الشاشة، سيُنقل المحتوى إلى صف جديد في الشبكة. هذا يساعد بقاء المحتوى منظم وقابل للعرض على مختلف الأجهزة متفاوتة العرض. مثال 23: تنظيم المحتوى عن طريق سطر الشبكة يشرح المثال كيفية ترصيف الأزرار وصناديق المحتوى على الصفحة باستخدام الشبكة. <!DOCTYPE html> <html> <head> <title>Script-Tutorials: Using a grid</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" /> <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script> <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script> </head> <body> <div id="page1" data-role="page"> <div data-role="header"> <h1>Using a grid</h1> </div> <div data-role="content"> <div class="ui-grid-a"> <div class="ui-block-a"> <p class="ui-bar ui-bar-b" style="height: 80px;"> This is first in the grid </p> </div> <div class="ui-block-b"> <p class="ui-bar ui-bar-b" style="height: 80px;"> This element is second in a grid </p> </div> <div class="ui-block-a"> <p class="ui-bar ui-bar-b" style="height: 80px;"> By reusing ui-block-a this wraps to a new row. </p> </div> <div class="ui-block-b"> <p class="ui-bar ui-bar-b" style="height: 80px;"> This is the final element in this grid </p> </div> </div> <div class="ui-grid-a"> <div class="ui-block-a"> <a href="#" data-role="button">Link 1</a> </div> <div class="ui-block-b"> <a href="#" data-role="button">Link 2</a> </div> </div> </div> <div data-role="footer"> <h4>Using a grid to align : jQuery mobile supports</h4> </div> </div> </body> </html> ستعرض الأجهزة الأكبر محتوى منظم في الشبكة، إذ سيتمدد المحتوى للاستفادة من مساحة الشاشة آنذاك. التخطيطات الشبكية كما هو موضح في المثال السابق أعلاه، تخطيط الشبكة يعتمد على بنية div: أنشئ عنصر div لاحتواء الشبكة، ومن ثم أضف الخلية داخلها المتمثلة بعناصر div أيضًا. يُتعامل مع الصفوف المتعددة عن طريق إضافة المزيد من خلايا div والتي يجب أن تُصنَّف ليكون لكل عمود الصنف ui-block الخاص به. يأخذ العنصر div الحاوي صنفًا يبدأ بـ ui-grid: الصنف ui-grid-a لإنشاء شبكة من عمودين، و ui-grid-b لإنشاء شبكة من ثلاثة أعمدة، وهكذا حتى ui-grid-d لشبكة مؤلفة من خمسة أعمدة. تأخذ الخلية المتمثلة بعناصر div صنفًا يبدأ بـ ui-block بناءً على ترتيبها: الصنف ui-block-a للخلية الأولى، والصنف ui-block-b للخلية الثانية، وهكذا حتى الصنف ui-block-e للخلية الخامسة. المثال 24: تخطيط شبكة في موقع مخصص للهاتف باستخدام jQuery mobile <!DOCTYPE html> <html> <head> <title>Script-tutorials: Grid layout with jQuery Mobile</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" /> <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script> <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script> </head> <body> <section id="page1" data-role="page"> <header data-role="header"> <h1>jQuery Mobile</h1> </header> <div class="content" data-role="content"> <h4>2 Colums</h4> <div class="ui-grid-b"> <div class="ui-block-a"> <p class="ui-bar ui-bar-b" style="height: 40px;">DIVISION A</p> </div> <div class="ui-block-b"> <p class="ui-bar ui-bar-b" style="height: 40px;">DIVISION B</p> </div> </div> <h4>3 Columns</h4> <div class="ui-grid-b"> <div class="ui-block-a"> <p class="ui-bar ui-bar-b" style="height: 40px;">DIVISION A</p> </div> <div class="ui-block-b"> <p class="ui-bar ui-bar-b" style="height: 40px;">DIVISION B</p> </div> <div class="ui-block-c"> <p class="ui-bar ui-bar-b" style="height: 40px;">DIVISION C</p> </div> </div> <h4>4 Columns</h4> <div class="ui-grid-c"> <div class="ui-block-a"> <p class="ui-bar ui-bar-b" style="height: 40px;">DIVISION A</p> </div> <div class="ui-block-b"> <p class="ui-bar ui-bar-b" style="height: 40px;">DIVISION B</p> </div> <div class="ui-block-c"> <p class="ui-bar ui-bar-b" style="height: 40px;">DIVISION C</p> </div> <div class="ui-block-d"> <p class="ui-bar ui-bar-b" style="height: 40px;">DIVISION D</p> </div> </div> <h4>5 Columns</h4> <div class="ui-grid-d"> <div class="ui-block-a"> <p class="ui-bar ui-bar-b" style="height: 40px;">DIVISION A</p> </div> <div class="ui-block-b"> <p class="ui-bar ui-bar-b" style="height: 40px;">DIVISION B</p> </div> <div class="ui-block-c"> <p class="ui-bar ui-bar-b" style="height: 40px;">DIVISION C</p> </div> <div class="ui-block-d"> <p class="ui-bar ui-bar-b" style="height: 40px;">DIVISION D</p> </div> <div class="ui-block-e"> <p class="ui-bar ui-bar-b" style="height: 40px;">DIVISION E</p> </div> </div> <h4>2 Rows of 3 Columns</h4> <div class="ui-grid-d"> <div class="ui-block-a"> <p class="ui-bar ui-bar-b" style="height: 40px;">DIVISION A</p> </div> <div class="ui-block-b"> <p class="ui-bar ui-bar-b" style="height: 40px;">DIVISION B</p> </div> <div class="ui-block-c"> <p class="ui-bar ui-bar-b" style="height: 40px;">DIVISION C</p> </div> <div class="ui-block-a"> <p class="ui-bar ui-bar-b" style="height: 40px;">DIVISION A</p> </div> <div class="ui-block-b"> <p class="ui-bar ui-bar-b" style="height: 40px;">DIVISION B</p> </div> <div class="ui-block-c"> <p class="ui-bar ui-bar-b" style="height: 40px;">DIVISION C</p> </div> </div> </div> <footer data-role="footer"> <h1>Alignment Grid-layou</h1> </footer> </section> </body> </html> بناء محتوى قابل للطي يمكن أن يكون المحتوى القابل للطي مخفيًا أو ظاهرًا مع وجود زر أو إمكانية لمسه لتغيير حالته (طيِّه إن كان مفتوحًا أو فتحه إن كان مطويًّا). ربما قد رأيت هذا النوع من السلوك على مواقع ويب أخرى سابقًا، خصوصًا في أقسام الأسئلة الشائعة. يكون عنوان الأسئلة والأجوبة غالبًا في مثل تلك المواقع ظاهرًا مع وجود زر مثل + أو - بجانبه للإِشارة إلى أنه يمكنك إظهار المحتوى وإخفاؤه. نفس هذه الوظيفة موجودة في jQuery Mobile. لإنشاء محتوى قابل للطي، إذ ستحتاج إلى إضافة الخاصية data-role="collapsible"‎ إلى العنصر الحاوي للعنصر الذي تريد جعله قابلًا للطي. المثال 25: بناء محتوى قابل للطي <!DOCTYPE html> <html> <head> <title>Script-tutorials: Collapsible Content</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" /> <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script> <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script> </head> <body> <div id="page1" data-role="page"> <div data-role="header"> <h1>Collapsible Content</h1> </div> <div data-role="content"> <div data-role="collapsible"> <h3>I'm a single collapsible element</h3> <p>I'm the content inside of the single collapsible element.</p> </div> <div data-role="collapsible-set"> <div data-role="collapsible" data-collapsed="false"> <h3>I'm expanded on page load</h3> <p>I am collapsible content that is visible on page load.</p> <p>That's because of the data-collapsed="false" attribute</p> </div> <div data-role="collapsible"> <h3>Expand me I have something to say</h3> <p>I am closed on page load, but still part of an accordion.</p> <div data-role="collapsible"> <h3>Wait, are you nested?</h3> <p>Yes! You can even nest your collapsible content!</p> </div> </div> </div> </div> <div data-role="footer"> <h4>Collapsible Content</h4> </div> </div> </body> </html> إضافة شريط أدوات في ترويسة الصفحة مثال 26: إعداد الترويسة <!DOCTYPE html> <html> <head> <title>Script-tutorials: Header toolbar</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" /> <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script> <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script> </head> <body> <div data-role="page"> <div data-role="header"> <h1>I am a header toolbar</h1> </div> </div> </body> </html> مثال 27: إضافة زر إلى ترويسة الصفحة <!DOCTYPE html> <html> <head> <title>Script-tutorials: Header toolbar</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" /> <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script> <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script> </head> <body> <div data-role="page"> <div data-role="header" data-position="inline"> <!-- first link --> <a href="#">Purchase</a> <h1>I am a header toolbar</h1> <!--second link --> <a href="#">Apply</a> </div> </div> </body> </html> لاحظ أنه لا يتوجب علينا تطبيق الخاصية data-role لتنسيق الرابط مثل حالة الأزرار. سيكون تنسيق الرابط مثل الزر تلقائيًا عند وضعه داخل شريط أدوات الترويسة (header toolbar). افتراضيًا، يُعرَض الرابط الأول في شريط أدوات الترويسة على الجانب الأيسر من الشريط. إرفاق شريط أدوات للتنقل شريط أدوات التنقل (navigation toolbar أو navbar)، هي ودجة (widget) موجودة في jQuery Mobile، تسمح لك بإضافة أزرار تنقل إلى صفحتك. مثال 28: صفحة مع شريط تنقل داخل شريط أدوات ترويسة الصفحة <!DOCTYPE html> <html> <head> <title>Script-tutorials: Header toolbar</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" /> <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script> <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script> </head> <body> <div data-role="page"> <div data-role="header" data-position="inline"> <!-- first link --> <a href="#">Purchase</a> <h1>I am a header toolbar</h1> <!--second link --> <a href="#">Apply</a> <div data-role="navbar"> <ul> <li><a href="#">Home</a> </li> <li><a href="#">About</a> </li> <li><a href="#">Services</a> </li> <li><a href="#">Blogs</a> </li> </ul> </div> </div> </div> </body> </html> تُنشَأ حاوية شريط التنقل كعنصر div مع الخاصية data-role="navbar"‎. لاحظ كيف أنَّ شريط التنقل مرتبط بشريط أدوات ترويسة الصفحة من خلال إنشائه داخله. سيحتوي العنصر ul على جميع الروابط التي نريد وضعها داخل شريط التنقل والتي تكون ضمن عناصر li. إضافة شريط أدوات الذيل تمامًا مثل شريط أدوات الترويسة، يمكنك إضافة شريط أدوات الذيل عن طريق إضافة الخاصية data-role="footer"‎ إلى حاوية العنصر. إليك جزء من شيفرة برمجية لإعداد شريط أدوات الصفحة: <div data-role="footer"> <h4>I am a footer toolbar</h4> </div> يجب أن يكون هذا الجزء مألوفًا لك إذ يشبه شريط أدوات الترويسة الذي تحدثنا عنه قبل قليل. لنقم بشيء جديد ونغيّر في شريط الأدوات الذيل عن طريق حذف العنصر h4 واستبداله ببعض الأزرار. مثال 29: إضافة وتنظيم الأزرار باستخدام مجموعة التحكم في ذيل الصفحة <!DOCTYPE html> <html> <head> <title>Script-tutorials: Header toolbar</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" /> <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script> <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script> </head> <body> <div data-role="page"> <div data-role="header" data-position="inline"> <!-- first link --> <a href="#">Purchase</a> <h1>I am a header toolbar</h1> <!--second link --> <a href="#">Apply</a> <div data-role="navbar"> <ul> <li><a href="#">Home</a> </li> <li><a href="#">About</a> </li> <li><a href="#">Services</a> </li> <li><a href="#">Blogs</a> </li> </ul> </div> </div> <!--content --> <div data-role="content"> <h3>CONTENT GOES HERE SHORTLY</h3> </div> <!--adding footer to your page with tool bar --> <div data-role="footer" class="ui-bar"> <div data-role="controlgroup" data-type="horizontal"> <a href="#" data-role="button">Features</a> <a href="#" data-role="button">Inquiry</a> <a href="#" data-role="button">Supports</a> </div> </div> </div> </body> </html> مثال 30: رصف الأزرار في شريط الأدوات في ذيل الصفحة يمكن استخدام خيارين لرصف الأزرار في شريط الأدوات في ذيل الصفحة: رصف المحتوى باستخدام الشبكة (grid): <div data-role="footer" class="ui-bar"> <div class="ui-grid-b"> <div class="ui-block-a"><a href="#" data-role="button">Features</a> </div> <div class="ui-block-b"><a href="#" data-role="button">Inquiry</a> </div> <div class="ui-block-c"><a href="#" data-role="button">Supports</a> </div> </div> </div> رصف المحتوى باستخدام مجموعة التحكم: <div data-role="footer" class="ui-bar"> <div data-role="controlgroup" data-type="horizontal"> <a href="#" data-role="button">Features</a> <a href="#" data-role="button">Inquiry</a> <a href="#" data-role="button">Supports</a> </div> </div> مثال 31: استخدام شريط التنقل في شريط أدوات ذيل الصفحة <!DOCTYPE html> <html> <head> <title>Script-tutorials: Header toolbar</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" /> <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script> <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script> </head> <body> <div data-role="page"> <div data-role="header" data-position="inline"> <!-- first link --> <a href="#">Purchase</a> <h1>I am a header toolbar</h1> <!--second link --> <a href="#">Apply</a> <div data-role="navbar"> <ul> <li><a href="#">Home</a> </li> <li><a href="#">About</a> </li> <li><a href="#">Services</a> </li> <li><a href="#">Blogs</a> </li> </ul> </div> </div> <!--content --> <div data-role="content"> <h3>CONTENT GOES HERE SHORTLY</h3> </div> <!--adding footer to your page with tool bar --> <div data-role="footer"> <div data-role="navbar"> <ul> <li><a href="#">Features</a> </li> <li><a href="#">Inquiry</a> </li> <li><a href="#">Supports</a> </li> </ul> </div> </div> </div> </body> </html> شريط التنقل (navbar) هي ودجة موجودة في jQuery Mobile تسمح لك بإضافة روابط تنقل في صفحتك، وعلى غرار نظام الشبكة المدمج، فإن شريط التنقل قادر على احتواء خمسة أعمدة. ولإضافة شريط التنقل إلى صفحتك، يجب عليك استخدام عنصر الحاوية مع الخاصية data-role="navbar"‎. يجب أن يكون لديك داخل الحاوية قائمة غير مرتبة ul مع كل عمود داخل عنصر li. تموضع أشرطة الأدوات تُوضع أشرطة الأدوات في العادة قبل وبعد قسم المحتوى، وهذا معيارٌ في تطوير الويب. في بعض الأحيان، قد تريد إبقاء رأس وذيل الصفحة مرئيًّا دائمًا، خاصة عند استخدام شريط التنقل (navbar)، وتوجد طريقتين لفعل هذا. يمكنك إما استخدام تموضع شريط الأدوات الثابت أو تملئ به الشاشة. التموضع الثابت عند استخدام موضع ثابت، سيتحقق jQuery Mobile من الصفحة لمعرفة هل شريط الأدوات ظاهر في العرض أم لا، فإذا كان شريط الأدوات خارج العرض، فسيُدرج في أعلى الصفحة أو أسفلها (بالاعتماد على ما إذا كان شريط الأدوات في رأس أو ذيل الصفحة) ليكون ظاهرًا للمستخدم. لجعل شريط الأدوات يستخدم الموضع الثابت، تحتاج إلى إضافة الخاصية data-position="fixed"‎ إلى شريط الأدوات. مثال 31: شريط الأدوات الثابت شكل صفحة HTML قبل التمرير إلى الأسفل: شكل صفحة HTML بعد التمرير إلى الأسفل: شيفرة HTML هي: <!DOCTYPE html> <html> <head> <title>Script-tutorials: Toolbars with jQuery Mobile</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" /> <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script> <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script> </head> <body> <div data-role="page"> <div data-role="header" data-position="fixed"> <a href="#">Buy Me</a> <h1>Fixed example</h1><a href="#">Apply Now</a> </div> <div data-role="content"> <a href="#" data-role="button">A button!</a> <p style="height: 400px;">This has been styled to take up more space</p> <p>This way you can see what happens when you scroll down the page</p> <p>The toolbars will reappear when you stop scrolling</p> <p>You can hide them by clicking or tapping the screen</p> </div> <div data-role="footer" data-position="fixed"> <div data-role="navbar"> <ul> <li><a href="#">Features</a> </li> <li><a href="#">Supports</a> </li> <li><a href="#">Contacts</a> </li> </ul> </div> </div> </div> </body> </html> وضع ملئ الشاشة يرتبط وضع ملئ الشاشة كثيرًا بالوضع الثابت، والفرق الرئيسي هو وضع الشريط فوق الصفحة بدلًا من أن يكونوا جزءًا منها. يمكن أن ينشئ هذا بعض مشاكل التنقل كالروابط التي قد تكون متاحة في أسفل أو أعلى الصفحة من الأشرطة التي هي الآن تحتهم مباشرة. من الجيد استخدام وضع ملئ الشاشة عند عرض معرض صور أو مقاطع فيديو. في هذه الأمثلة، يمكن وضع عناصر التحكم في شريط التنقل، مما يُتيح للمستخدم فتح وإغلاق عناصر التحكم عند الحاجة. ستحتاج إلى إضافة الخاصية data-fullscreen="true"‎ إلى عنصر div الذي يملك أيضا الخاصية data-role="page"‎ لاستخدام وضع ملئ الشاشة. ويجب عليك التأكد من أن كل من أشرطة أدوات ترويسة وذيل الصفحة تحتوي على data-position="fixed"‎. يجب علينا تغيير هذا السطر من التعليمات البرمجية السابقة <div data-role="page"‎> إلى هذا السطر <div data-role="page" data-fullscreen="true"‎> مثال 32: شريط أدوات في وضع ملئ الشاشة <!DOCTYPE html> <html> <head> <title>Script-tutorials: Toolbars with jQuery Mobile</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" /> <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script> <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script> </head> <body> <div data-role="page" data-fullscreen="true"> <div data-role="header" data-position="fixed"> <a href="#">Buy Me</a> <h1>Full Screen </h1><a href="#">Apply Now</a> </div> <div data-role="content"> <a href="#" data-role="button">A button!</a> <p style="height: 400px;">This has been styled to take up more space</p> <p>This way you can see what happens when you scroll down the page</p> <p>The toolbars will reappear when you stop scrolling</p> <p>You can hide them by clicking or tapping the screen</p> </div> <div data-role="footer" data-position="fixed"> <div data-role="navbar"> <ul> <li><a href="#">Features</a> </li> <li><a href="#">Supports</a> </li> <li><a href="#">Contacts</a> </li> </ul> </div> </div> </div> </body> </html> تذكر أنَّه يمكن الوصول إلى العناصر التي تغطيها أشرطة الأدوات عند استخدام وضع ملئ الشاشة عن طريق الضغط أو لمس في مكان ما على الشاشة لإخفاء الشريط. إضافة تنقل مستمر ليكن لدينا عنصر div مع الخاصيات data-role="footer"‎، و data-position="fixed"‎ و data-id="rps"‎، أول خاصيتين مطلوبتين لإنشاء شريط أدوات الذيل واستخدام التموضع الثابت، وأما بالنسبة للخاصية data-id=”rps”‎ فهي ستُبقِي شريط التنقل ظاهرًا أثناء التنقل بين الصفحات. ويعمل هذا فقط عندما تكون القيمة داخل الخاصية data-id هي نفسها في الصفحة الحالية التي ستنتقل إليها. مثال 31: إضافة تنقل مستمر معاينة الصفحة features.html: الانتقال إلى الصفحة supports.html: الانتقال إلى الصفحة contacts.html: المدخلات والأزرار تُنشئ العديد من أنواع عناصر الإدخال في HTML أزرارًا. في أي وقت تستخدم فيه عنصر إدخال مع الخاصية type مضبوطةً إلى إحدى القيم: submit، أو reset، و button، أو image، سيتحول عنصر الإدخال تلقائيًا إلى زر. بما أن أنواع المدخلات هذه تتحول تلقائيًا إلى أزرار، لا تحتاج إلى إضافة الخاصية data-role="button"‎ كما فعلت عند استخدام زر ذي رابط؛ فقط في حالة كنت تتساءل، يتحول عنصر الزر أيضًا تلقائيًا إلى نمط زر ولا يتطلب أي شيفرة إضافية. مثال 32: المدخلات والأزرار (عناصر النموذج) <!DOCTYPE html> <html> <head> <title>Script-tutorials: Buttons jQuery Mobile</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" /> <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script> <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script> </head> <body> <div data-role="page"> <div data-role="header"> <h1>Buttons / Inputs</h1> </div> <div data-role="content"> <p>Link-based button</p> <a href="#" data-role="button">Link-based</a> <p><button> Element</p> <button type="button">Button</button> <p><input type="submit"></p> <input type="submit" value="Submit" /> <p><input type="button"></p> <input type="button" value="Button" /> <p><input type="reset"></p> <input type="reset" value="Reset" /> <p><input type="image"></p> <input type="image" value="Image" /> </div> </div> </body> </html> تجاوز التنسيق الافتراضي للزر بشكل افتراضي، تملك الأزرار مظهرًا معينًا افتراضيًّا. لمَّا كان الزر يظهر بشكل جيد في أغلب الهواتف والأجهزة المحمولة، فإنه قد يظهر بمظهر غير جميل عندما يقترن بتصميمك. لحسن حظنا، يمكننا تحسين جمالية الزر يدويًّا. المثال 33: إنشاء أزرار مع زوايا مدورة ومربعة <!DOCTYPE html> <html> <head> <title>Script-tutorials: Buttons jQuery Mobile</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" /> <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script> <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script> </head> <body> <div data-role="page"> <div data-role="header"> <h1>Buttons</h1> </div> <div data-role="content"> <a href="#" data-role="button" data-corners="false">Squared</a> <a href="#" data-role="button">Rounded</a> <a href="#" data-role="button" data-corners="false">Squared</a> </div> </div> </body> </html> إزالة الظل من الأزرار هنالك خيار آخر قد ترغب في تغييره وهو مظهر الظل أسفل الزر. يمكن تغيير هذا باستخدام الخاصية data-shadow="false"‎. لا تقتصر على استخدام خاصية data واحدة فقط لكل عنصر، بل يمكنك الجمع بينها للحصول على تنسيقات مختلفة. المثال34: تغيير مظهر الزر مع الخاصية data <!DOCTYPE html> <html> <head> <title>Script-tutorials: Buttons jQuery Mobile</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" /> <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script> <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script> </head> <body> <div data-role="page"> <div data-role="header"> <h1>Buttons</h1> </div> <div data-role="content"> <a href="#" data-role="button" data-shadow="false">No Shadow</a> <a href="#" data-role="button">Shadow</a> <a href="#" data-role="button" data-corners="false" data-shadow="false">Squared no Shadow</a> </div> </div> </body> </html> تغيير حجم الزر عندما أنشأنا سابقًا الزر، لم نقلق بشأن حجمه، في حين قد لا تحتاج إلى تغيير الحجم الافتراضي للزر، لكن قد تواجه بعض المشاكل أو بعض النتائج غير المتوقعة مع الحجم الافتراضي. مثال 35: تغيير عرض الزر الافتراضي مع الخاصية data <!DOCTYPE html> <html> <head> <title>Script-tutorials: Buttons jQuery Mobile</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" /> <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script> <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script> </head> <body> <div data-role="page"> <div data-role="header"> <h1>Buttons</h1> </div> <div data-role="content"> <a href="#" data-role="button">Full Width Button</a> <a href="#" data-role="button" data-inline="true">Inline Button</a> </div> </div> </body> </html> أضفنا الخاصية data-inline="true"‎ إلى العنصر، وذلك يجعل الزر يستخدم مساحة تعادل المحتوى الذي بداخله فقط. المثال 36: وضع الزر في سطر <!DOCTYPE html> <html> <head> <title>Script-tutorials: Buttons jQuery Mobile</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" /> <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script> <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script> </head> <body> <div data-role="page"> <div data-role="header"> <h1>Buttons</h1> </div> <div data-role="content"> <a href="#" data-role="button" data-inline="true">An Inline Button</a> <a href="#" data-role="button" data-inline="true">Also an Inline Button</a> </div> </div> </body> </html> كلا الزرّين يملكان الخاصية data-inline="true"‎ وهذا يعني أن كلا الزرّين سيظهران بجانب بعضهما البعض، وإضافة المزيد من الأزرار مع استخدام نفس الخاصية سيستمر بوضعهم بجانب بعضهم البعض إلى أن يصل إلى الحد الأقصى لعرض الصفحة. ضبط عرض الزر وموقعه باستخدام الشبكة مثال 37: ضبط عرض الزر وموقعه باستخدام الشبكة <!DOCTYPE html> <html> <head> <title>Script-tutorials: Buttons jQuery Mobile</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" /> <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script> <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script> </head> <body> <div data-role="page"> <div data-role="header"> <h1>Buttons</h1> </div> <div data-role="content"> <div class="ui-grid-a"> <div class="ui-block-a"><a href="#" data-role="button">Left</a> </div> <div class="ui-block-b"><a href="#" data-role="button">Right</a> </div> </div> </div> </div> </body> </html> في هذا المثال، يمكننا رؤية شبكة بسيطة مكونة من عمودين. الصنف ui-block-a ينظم المحتوى في العمود الأول من الشبكة في حين يرصف الصنف ui-block-b المحتوى في العمود الثاني. ترجمة -وبتصرّف- للمقال jQuery Mobile Lesson 4 لصاحبه Andrew اقرأ أيضًا الدرس التالي: الأيقونات والأزرار وإنشاء تنسيقات مخصصة الدرس السابق: اتجاه الصفحة وأحداثها
  9. يتحدث هذا الدرس الجديد عن اتجاه صفحة الهاتف، وأحداث الصفحة (مثل pagebeforecreate، و pagecreate، و pageinit ...إلخ)، واللمس وأحداث التمرير (مثل swipe) وأحداث الفأرة الافتراضية. ستجد العديد من الأمثلة تشرح لك هذه الأحداث. هذا الدرس جزء من سلسلة دروس تشرح jQuery Mobile: الدرس الأول: البداية، بناء وتقديم محتوى الدرس الثاني: التضمين، تهيئة الصفحة، التنقل بين الصفحات وأحداث التحميل الدرس الثالث: اتجاه الصفحة وأحداثها الدرس الرابع: ربط صفحات خارجية وتنظيم المحتوى بنظام الشبكة وبناء محتوى قابل للطي الدرس الخامس: الأيقونات والأزرار وإنشاء تنسيقات مخصصة الدرس السادس: إنشاء القوائم وتنسيقها وإنشاء نماذج البحث وتسجيل الدخول التكيف مع حدث الاتجاه هنالك خيارين/وضعين لاتجاه الشاشة عند عرض جهاز الهاتف، فعند عرض الصفحة عموديًا (portrait)، هذا يعني أن ارتفاع الشاشة أكبر من عرضها، وعند عرض الصفحة أفُقيًّا (landscape)، سيكون عرض الصفحة أكبر من طولها. ما لم يُقفل الجهاز على وضع عرض واحد، يمكن أن تستدير الشاشة وسيتحول المحتوى تلقائيا للاستفادة من المساحة الإضافية، بينما يعالج jQuery Mobile تغيير حجم العديد من العناصر، قد تحتاج إلى تشغيل دالة معينة كلما تغيّر وضع الشاشة. المثال 7: استخدام الحدث orientationchange، حدث تغيير الاتجاه <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.css"> <script src="http://code.jquery.com/jquery-1.11.3.min.js"></script> <script src="http://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.js"></script> <script> $(document).on("pagecreate",function(event){ $(window).on("orientationchange",function(){ if(window.orientation == 0) { $("p").text("The orientation has changed to portrait!").css({"background-color":"yellow","font-size":"300%"}); } else { $("p").text("The orientation has changed to landscape!").css({"background-color":"pink","font-size":"200%"}); } }); }); </script> </head> <body> <div data-role="page"> <div data-role="header"> <h1>The orientationchange Event</h1> </div> <div data-role="main" class="ui-content"> <p>Try to rotate your device!</p> <p><b>Note:</b> You must use a mobile device, or a mobile emulator to see the effect of this event.</p> </div> <div data-role="footer"> <h1>Footer Text</h1> </div> </div> </body> </html> <!DOCTYPE html> <html> <head> <title>Script-tutorials: Page orientaton Event</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.css"> <script src="http://code.jquery.com/jquery-1.11.3.min.js"></script> <script> $(document).on('pageinit', function() { $(window).on('orientationchange', function(e) { $("#mode").html('orientation is currently '+e.orientation); }); }); </script> <script src="http://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.js"></script> </head> <body> <div data-role="page" id="mode"> <div data-role="header"><h1>Page orientaton Event</h1></div> <div data-role="main" class="ui-content"> <p>Content in orientation</p> <a href="pageexist.html" data-role="button">External Page Exist</a> <a href="page_notexist.html" data-role="button">No Page Exist</a> <p>Try to rotate your device!</p> <p><b>Note:</b> You must use a mobile device, or a mobile emulator to see the effect of this event.</p> </div> <div data-role="footer"> <h1>Script-tutorials.com</h1> </div> </div> </body> </html> تهيئة الصفحة في jQuery mobile المثال 8: تهيئة الصفحة في jQuery mobile شيفرة الصفحة قبل تهيئة jQuery Mobile: <!-- begin first page --> <section id="page1" data-role="page"> <header data-role="header"><h1>jQuery Mobile</h1></header> <div data-role="content"> <p>First page!</p> </div> <footer data-role="footer"><h1>Footer</h1></footer> </section> <!-- end first page → شيفرة الصفحة بعد تهيئة jQuery Mobile: <!-- begin first page --> <section class="ui-page ui-body-c ui-page-active" data-url="page1" id="page1" data-role="page"> <header role="banner" class="ui-bar-a ui-header" data-role="header"> <h1 aria-level="1" role="heading" tabindex="0" class="ui-title">jQuery Mobile</h1> </header> <div role="main" data-role="content" class="ui-content"> <p>First page!</p> </div> <footer role="contentinfo" class="ui-bar-a ui-footer" data-role="footer"> <h1 aria-level="1" role="heading" tabindex="0" class="ui-title">Footer</h1> </footer> </section> <!-- end first page → تعطي كلا الشيفرتين نفس النتيجة: عند إنشاء تطبيق jQuery، من الشائع ربط معالجات الحدث (event handlers) في حدث تحميل الصفحة (document load)، ويمكنك فعل شيء مشابه باستخدام أحداث عرض الصفحة وإخفاء الصفحة في jQuery Mobile، لكن كن حذرًا، بما أن أحداث عرض وإخفاء الصفحة تعمل في كل مرة يحدث فيها انتقالًا للصفحة. فقد تربط معالجات الحدث أكثر من مرة، فعلى سبيل المثال، إذا ربطت مستمع حدث الضغط إلى عنصر داخل حدث عرض الصفحة (page show event)، فإن مستمع حدث الضغطة يرتبط في كل مرة تظهر فيها الصفحة، وهذا جيد إذا كنت تستخدم تلك الصفحة فقط، لكن إذا ذهب المستخدم لتلك الصفحة عدة مرات، فإن مستمع الحدث سيرتبط عدة مرات. لحل هذه المشكلة، يمكنك إما التحقق لمعرفة إذا كان معالج الحدث قد رُبط بالفعل (لكن لا تربطه مرة أخرى)، أو مسح الارتباط في كل مرة قبل إعادة الربط. وإذا استخدمت الطريقة الأخيرة، فاستعمال مجالات الأسماء (namespacing) سيكون مُفيدًا. للمزيد من المعلومات حول الأحداث ذات الأسماء المصنفة ضمن مجالات أسماء، راجع هذا التوثيق. الأحداث المحدِّدة ضمن مجالات أسماء هي أداة مفيدة جدًا يمكن وضعها في صندوق أدوات jQuery. استخدام الحدث pagebeforecreate لإضافة خاصية بشكل ديناميكي يُستخدم الحدث pagebeforecreate عندما تملك محتوى تريد تغييره قبل أن يمتلك jQuery Mobile فرصة لقفله وكتابة data-roles وخاصيات عناصر الصفحة إلى DOM. المثال 9: استخدام الحدث pagebeforecreate لإضافة خاصية بشكل ديناميكي يبدأ الملف كملف HTML قياسي يستخدم jQuery Mobile، لكننا بدأنا بالعنصر script، تُستخدم بعض الشيفرات البرمجية لـ jQuery لربط الحدث pagebeforecreate إلى الصفحة، ويتم هذا باستخدام الدالة ‎.on()‎ المتوفرة عند استخدام الإصدار jQuery 1.7 ومابعده. عندما يبحث الحدث pagebeforecreate على أية عناصر تملك الخاصية class="modify"‎ وتطبق الخاصية datainset="true"‎ إلى أي واحدة يُعثَر عليها باستخدام الدالة ‎.attr()‎. يرى jQuery Mobile الخاصية data-inset="true"‎ ويضعها في قائمة بسبب عمل الحدث pagebeforecreate قبل إضافة شيفرة الصفحة إلى DOM. <!DOCTYPE html> <html> <head> <title>Script-tutorials: Developing with jQuery Mobile</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" /> <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script> <script> $(document).on('pagebeforecreate', function(event) { $(".modify").attr('data-inset','true'); }); </script> <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script> </head> <body> <div data-role="page" id="home"> <div data-role="header"><h1>pagebeforecreate event</h1></div> <div data-role="content"> <p>The following list will be inset during the pagebeforecreate event</p> <ul class="modify" data-role="listview"> <li>A</li> <li>B</li> <li>C</li> </ul> </div> </div> </body> </html> استخدام الحدث pagecreate يمكن استخدام الحدث pagecreate إما لتطبيق الودجات (widgets) الخاصة بك أو استخدام ودجة (widget) مدمجة أو إضافة تحكم يوفرها jQuery Mobile. المثال 8: استخدام الحدث pagecreate بالاقتران مع الإضافة listview تبدأ الشيفرة البرمجية كصفحة قياسية باستخدام jQuery Mobile، وتستخدم الدالة ‎.on()‎ الحدث pagecreate للعمل. هنالك مُحدد (selector) لإيجاد أي عنصر في الصفحة التي تملك الخاصية class="modify"‎ ومن ثم يُضيف الخاصية data-inset="true"‎. وبعد فعل ذلك، يمكنك أن ترى عمل الدالة listview()‎. تُعرف هذه الدالة على أنها الإضافة listview وتُستخدم لتطبيق نمط وشكل أي قائمة. السطر 11 هو نهاية الدالة ‎.on()‎، والتي هي ربط للحدث pagecreate. هنالك عنصر ul يحتوي فقط على الخاصية class="modify"‎؛ الخاصية data-role="listview"‎ لن تكون موجودة ولا الخاصية data-inset="true"‎. <!DOCTYPE html> <html> <head> <title>Script-tutorials: Developing with jQuery Mobile</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" /> <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script> <script> $(document).on('pagecreate', function(event) { $(".modify").attr('data-inset','true').listview(); }); </script> <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script> </head> <body> <div data-role="page" id="home"> <div data-role="header"><h1>pagecreate event</h1></div> <div data-role="content"> <p>The following list will be styled during the pagecreate event</p> <ul class="modify"> <li>A</li> <li>B</li> <li>C</li> </ul> </div> </div> </body> </html> استخدام الحدث pageinit أفضل وصف للحدث pageinit هو: «استخدمه كما لو تستخدم الدالة ‎$(document).ready()‎ في jQuery. يعمل هذا الحدث بعد تحميل DOM وعمل جميع الودجات والإضافات، ويعمل أيضًا كلما تُحمّلت الصفحة إما مباشرةً أو من خلال استدعاء AJAX من الصفحة الأخرى، وسيعمل هذا الحدث مرة واحدة عند تضمينه في DOM. استخدام pageinit عند تحميل صفحة ثانية يجب أن يكون الإعداد الأولي للصفحة مألوفًا بالنسبة لك الآن؛ في البداية، يمكنك أن ترى أنه يستخدم نفس الأسلوب لربط الحدث pageinit كما رُبِط الحدثpagebeforecreate والحدث pagecreate. الفرق هو في استخدام مُحدد (selector) لعنصر ذي المُعرِّف id="away"‎ في الدالة ‎.on()‎ لربط الدالة alert()‎ التي ستعمل فقط على الصفحة التي تطابق ذلك المحدد عند تحميلها لأول مرة في DOM. بالنزول إلى الأسفل أكثر، سترى أن الصفحة أُعدّت مع عنصر div باستخدام الخاصية data-role="page"‎. المثال 9: استخدام pageinit عند تحميل الصفحة الثانية <!DOCTYPE html> <html> <head> <title>Script-tutorials: Developing with jQuery Mobile</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" /> <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script> <script> $(document).on('pageinit','#away', function(event) { alert("The pageinit event has been run"); }); </script> <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script> </head> <body> <div data-role="page" id="home"> <div data-role="header"><h1>pageinit event</h1></div> <div data-role="content"> <p>I am the #home page</p> <a href="#away" data-role="button">Go Away</a> </div> </div> <div data-role="page" id="away"> <div data-role="header"><h1>pageinit event</h1></div> <div data-role="content"> <p> I am the #away page. The pageinit event runs on first page load. </p> <a href="#home" data-role="button">Go Back</a> </div> </div> </body> </html> الصورة الأولى للمعاينة في المتصفح. الصور الثانية تظهر عند الضغط على الزر Go Away في المتصفح. الصورة الثالث هي للصورة المُهيَّأة. الآن لننظر في نمط تهيئة الصفحة في jQuery Mobile. المثال 10: تغريدة جميلة دون سكربت التهيئة <!DOCTYPE html> <html> <head> <title>Script-Tutorials: My first mobile site</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css"/> <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script> <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script> <style> img {max-width:100%;} p{text-align:center;} </style> </head> <body> <!-- begin first page --> <section id="page1" data-role="page"> <header data-role="header"> <h1>Nice Tweet</h1> </header> <div data-role="content" class="content"> <p>Twitter feed goes here.</p> <p><a href="#page2" data-role="button">Settings</a></p> <p><img src="images/twitter-logo-hashtag.jpg" alt="Twitter settings" /></p> <p>Powered by jQuery Mobile</p> </div> <footer data-role="footer"> <h2>Because the world needed another Twitter app.</h2> </footer> </section> <!-- end first page --> <!-- Begin second page --> <section id="page2" data-role="page"> <header data-role="header"> <h1> Nice Tweet: Settings</h1> </header> <div data-role="content" class="content"> <p>Settings go here. <a href="#page1" data-role="button">Go back</a></p> <p><img src="images/business-twitter-page-img.png" alt="Settings" /></p> <p style="text-align:center;">Powered by jQuery Mobile</p> </div> <footer data-role="footer"> <h2>Because the world needed another Twitter app.</h2> </footer> </section> <!-- end second page --> </body> </html> <script> $(document).ready(function() { // Refresh the feed on first load // (pretend we've written this function elsewhere) refreshFeed(); $("#page1").bind("pageshow", function(event, ui) { // Refresh the feed on subsequent page shows refreshFeed(); }) }) </script> أحداث اللمس عند تفاعل المستخدم مع موقعك عن طريق اللمس، ستعمل أحداث اللمس، ويمكنك الاستفادة من هذه الأحداث لعمل دوال مخصصة. استخدام أحداث tap الفرق الرئيسي بين حدث النقر click وحدث بدء اللمس touchstart هو حوالي 300 ملي ثانية. في حين أن هذا لا يبدو فارقًا كبيرًا في الوقت، لكن تأخير ثلث ثانية قد يجعل موقعك أو تطبيقك يبدو بطيئًا وغير متجاوب. بينما يُستخدم الحدث tap بشكل افتراضي على الروابط، والقوائم، وودجات وإضافات jQuery Mobile المتشابهة، يمكنك استخدام الحدث tap لتنفيذ دوال مخصصة في مختلف عناصر صفحتك. مثال 11: استخدام الحدثين tap و taphold <!DOCTYPE html> <html> <head> <title>Developing with jQuery Mobile</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" /> <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script> <script> $(document).on("pageinit", function(){ $("#home").on('tap', '#image', function(event, ui) { var tapCaption = $(this).data("tap"); $("#caption").addClass("comment").html(tapCaption); }); $("#home").on('taphold','#caption', function(event, ui) { var $this = $(this); var tapholdCaption = $this.data("appTaphold"); $this.html(tapholdCaption); }); }); </script> <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script> <style type="text/css"> img {max-width: 100%} .comment {background: #FFF;border-radius: 5px; border: 2px solid #000;padding: 5px} </style> </head> <body> <div data-role="page" id="home"> <div data-role="header"><h1>Tap Events</h1></div> <div data-role="content"> <p>Tap or tap-and-hold the image below.</p> <img id="image" src="images/golden_gate.jpg" alt="An image of a river" data-tap="You tapped the picture, try tap-and-holding on this caption" /> <div id="caption" data-app-taphold="This picture was taken during a flood.">Caption</div> </div> </div> </body> </html> يجب ربط الحدثين tap و taphold إما في الدالة document.ready()‎ أو داخل الحدث pageinit. بما أننا نعلم بالفعل أنه من غير المستحسن استخدام الدالة document.ready()‎ مع jQuery Mobile، لذلك سنربط الحدث pageinit باستخدام الدالة ‎.on()‎. داخل الدالة، يمكنك رؤية الدالة ‎.on()‎ تربط الحدث tap إلى عنصر يملك الخاصية id="image"‎. استخدام أحداث التمرير من الشائع التمرير في الهاتف عند التنقل في معرض صور، وحذف بريد إلكتروني، وإحضار معلومات الاتصال …إلخ. يمكنك مع jQuery Mobile استخدام ثلاثة أحداث متعلقة بالتمرير هي: swipe، و swipeleft، و swiperight. تشبه عملية التمرير (swipe) في الهاتف المحمول عملية النقر والسحب (click-and-drag ) في الحاسوب. ليعمل أي حدث من أحداث التمرير، يجب أن يتحرك اللمس على أكثر من 30 بيكسل أفقيًا ويبقى 1 ثانية ليكتمل، كما أنه لا يجب أن يتحرك أكثر من 20 بيكسل عموديًا وإلا سيُلغى تشغيل الحدث. مثال 12: استخدام أحداث التمرير ستُعرض الصورة في الأسفل عند تمرير المربع إلى اليمين كما يظهر على متصفح هاتفك في جهازك المحمول. <!DOCTYPE html> <html> <head> <title>Developing with jQuery Mobile</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" /> <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script> <script> $(document).on('pageinit', function() { $("#home").on('swipe','#swipe', function(event, ui) { $("#caption").html("Swipe detected!"); }); $("#home").on('swipeleft','#swipe-box', function(event, ui) { ("#caption").html("Swipe to the left detected!"); }); $("#home").on('swiperight','#swipe-box', function(event, ui) { $("#caption").html("Swipe to the right detected!"); }); }); </script> <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script> <style type="text/css"> #swipe-box { width: 200px; height: 200px; background: #FFF; border: 2px solid #000 } .comment { background: #FFF; border-radius: 5px; border: 2px solid #000; padding: 5px } </style> </head> <body> <div data-role="page" id="home"> <div data-role="header"><h1>Swipe Events</h1></div> <div data-role="content"> <p id="swipe">Take a swipe this text or at the box below.</p> <div id="swipe-box"></div> <br /> <div id="caption" class="comment">Waiting for swipe...</div> </div> </div> </body> </html> أحداث الفأرة الافتراضية أحداث الفأرة الافتراضية هي حل لمشاكل التوافق بين متصفحات الهاتف والحاسوب، فعلى سبيل المثال، تدعم بعض المتصفحات حدثًا يسمى touchstart في حين بعض المتصفحات الأخرى لا تدعمه. تدعم متصفحات الحاسوب الحدث mousemove وتدعم الحومان (hover) عبر استخدام الحدث mouseover في حين تواجه أجهزة الهاتف صعوبةً في محاكاة أو استخدام الحدث الصحيح. هذه المشاكل حلتها jQuery Mobile عن طريق استخدام أحداث الفأرة الافتراضية، فعند تحميل صفحة مع jQuery Mobile، سيتأكد المتصفح من دعم الحدث. وستُدعم الأحداث آنذاك بناءً على أحداث الفأرة الافتراضية، بينما يحدث هذا في الخلفية، يمكنك ربط أحداث الفأرة الافتراضية لتشغيل دوال محدد أو حتى الحصول على بيانات يمكن استخدامها في دوال أخرى. أحداث الفأرة الافتراضية المتاحة هي: vmouseover vmousedown vmousemove vmouseup vclick vmousecancel ستجد في الأسفل جزءًا من شيفرة برمجية موجودة في الوسم <head> لاستخدام الأحداث vmousedown و vmousemove و vmouseover. المثال 13: مقتطف شيفرة برمجية لأحداث vmousedown، و vmousemove و vmouseover <script> $(function(){ $(document).on("vmousedown", "p", function() { $(this).append('<span style="color:#108040;">vmousedown...</span>'); }); }); </script> المثال 14: الحدث vmousedown في jQuery mobile بمجرد النقر على التسمية التوضيحية داخل المتصفح، سيُطلَق الحدث vmousedown. <!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Script-tutorials: vmousedown</title> <link rel="stylesheet" href="//code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.css" /> <script src="//code.jquery.com/jquery-1.10.2.min.js"></script> <script> $( function(){ $(document).on("vmousedown", "p", function() { $(this).append('<span style="color:#108040;"> vmousedown...</span>'); }); }); </script> <script src="//code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.js"></script> </head> <body> <div data-role="page"> <div data-role="header"><h1>Vmousedown event example</h1></div> <div data-role="content"> <p>Touch here to see what happens.</p> </div> </div> </body> </html> المثال 15: الحدث vmouseup في jQuery mobile <!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Script-tutorials: vmouseup</title> <link rel="stylesheet" href="//code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.css" /> <script src="//code.jquery.com/jquery-1.10.2.min.js"></script> <script> $(function() { $(document).on("vmouseup", "p", function() { $(this).append('<span style="color:#108040;"> vmouseup when you click i will not until you releases the click button up...</span>'); }); }); </script> <script src="//code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.js"></script> </head> <body> <div data-role="page"> <div data-role="header"> <h1>VmouseUp event example</h1> </div> <div data-role="content"> <p>Touch here to see what happens.</p> </div> </div> </body> </html> المثال 16: الحدث vmouseup في jQuery mobile <!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Script-tutorials: vmouseover</title> <link rel="stylesheet" href="//code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.css" /> <script src="//code.jquery.com/jquery-1.10.2.min.js"></script> <script> $(function() { $(document).on("vmouseover", "p", function() { $(this).append('<span style="color:#108040;"> vmouseover I will not appear unless you move the pointer over that touche and see...</span>'); }); }); </script> <script src="//code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.js"></script> </head> <body> <div data-role="page"> <div data-role="header"> <h1>VmouseOver event example</h1> </div> <div data-role="content"> <p>Touch here to see what happens.</p> </div> </div> </body> </html> بناء موقعك الأول المخصص للهواتف باستخدام jQuery mobile الترويسة (Header) هذا القسم هو أول شيء يراه المستخدم، وقد يكون أبرز خاصية لموقع الهاتف، ويُعلم هذا المستخدمين بمكانهم، وقد يتضمن شريط بحث، وزر دعوة إلى إجراء (call-to-action)، و/أو شعار. قسم المحتوى (Content) يحتوي هذا القسم على ما يبدو عليه: أزرار، ونصوص وكل شيء آخر لم يتضمن في الأقسام الأخرى. يضم هذا القسم جوهر موقعك ويعرض كل ما تريد أن يراه المستخدم أو يقضي فيه وقته. تذييل الصفحة (Footer) غالبا ما يُتجاهل هذا القسم لكنه منطقة مهمة من موقعك، فيمكن أن يحتوي على كل شيء بدءًا من الروابط الإضافية إلى سطر بسيط لملكية الموقع. عند تطوير مواقع الويب للهواتف، يُحذَف في العادة هذا القسم ويُستبدل بشريط تنقل أو عنصر ثابت آخر. مثال 16: تخطيط أساسي للهواتف <!DOCTYPE html> <html> <head> <title>Script-tutorials: My first mobile site</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" /> <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script> <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script> </head> <body> <div data-role="page"> <div data-role="content"> Welcome message. </div> </div> </body> </html> مثال 17: إضافة ترويسة وتذييل إلى موقعك المخصص للهواتف <!DOCTYPE html> <html> <head> <title>Script-tutorials: My first mobile site</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" /> <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script> <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script> </head> <body> <div data-role="page"> <div data-role="header"> My First Mobile Site </div> <div data-role="content"> Welcome to my first mobile site. </div> <div data-role="footer"> Tutors footer! </div> </div> </body> </html> المثال 18: تنسيق المحتوى النصي في الموقع عبر تضمين وسوم التنسيق <!DOCTYPE html> <html> <head> <title>Script-tutorials: My first mobile site</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" /> <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script> <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script> </head> <body> <div data-role="page"> <div data-role="header"> <h1>My First Mobile Site</h1> </div> <div data-role="content"> <p>Welcome to my first mobile site.</p> <p>Try me on all of your mobile devices! You can use any <strong>valid HTML</strong> on this page</p> <p style="text-align:center;">Powered by jQuery Mobile</p> </div> <div data-role="footer"> <h3>Tutors footer!</h3> </div> </div> </body> </html> المثال 19: إضافة صور ذات حجم متغير (متجاوبة) إلى الموقع <!DOCTYPE html> <html> <head> <title>My first mobile site</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" /> <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script> <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script> <style> img { max-width: 100%; } </style> </head> <body> <div data-role="page"> <div data-role="header"> <h1>My First Mobile Site</h1> </div> <div data-role="content"> <p>Welcome to my first mobile site.</p> <p>Try me on all of your mobile devices! You can use any<strong>valid HTML</strong> on this page</p> <img src="images/golden_gate.jpg" alt="Golden Gate Bridge" /> <p style="text-align:center;">Powered by jQuery Mobile</p> </div> <div data-role="footer"> <h3>Tutor footer!</h3> </div> </div> </body> </html> المثال 20:الربط مع صفحة ثانية عبر الحدث vmouseup <!DOCTYPE html> <html> <head> <title>Script-Tutorials: My first mobile site</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" /> <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script> <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script> <style> img { max-width: 100%; } </style> </head> <body> <div id="pageone" data-role="page"> <div data-role="header"> <h1>My First Mobile Site</h1> </div> <div data-role="content"> <p>Welcome to my first mobile site.</p> <p>Try me on all of your mobile devices! You can use any <strong>valid HTML</strong> on this page</p> <img src="images/golden_gate.jpg" alt="Golden Gate Bridge" /> <a href="#pagetwo" data-role="button">Go to Page 2</a> <p style="text-align:center;">Powered by jQuery Mobile</p> </div> <div data-role="footer"> <h3>Tutor footer!</h3> </div> </div> <div id="pagetwo" data-role="page"> <div data-role="header"> <h1>My First Mobile Site</h1> </div> <div data-role="content"> <p>You've made it to page 2!</p> <p>Isn't that awesome?</p> <a href="#pageone" data-role="button">Go Back to Page 1</a> <p style="text-align:center;">Powered by jQuery Mobile</p> </div> <div data-role="footer"> <h3>Viva la footer!</h3> </div> </div> </body> </html> مثال 21: ثلاثة صفحات داخلية في ملف HTML واحد <!DOCTYPE html> <html> <head> <title>Script-Tutorials: My first mobile site</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" /> <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script> <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script> <style> img { max-width: 100%; } </style> </head> <body> <!-- begin first page --> <section id="page1" data-role="page"> <header data-role="header"> <h1>jQuery Mobile</h1> </header> <div data-role="content" class="content"> <p>First page!</p> <p>Welcome to my first mobile site.</p> <p>Try me on all of your mobile devices! You can use any<strong>valid HTML</strong> on this page</p> <img src="images/golden_gate.jpg" alt="Golden Gate Bridge" /> <p style="text-align:center;">Powered by jQuery Mobile</p> <p><a href="#page2" data-role="button">Go to Second Page</a> </p> </div> <footer data-role="footer"> <h1>Footer</h1> </footer> </section> <!-- end first page --> <!-- Begin second page --> <section id="page2" data-role="page"> <header data-role="header"> <h1>jQuery Mobile</h1> </header> <div data-role="content" class="content"> <p>Second page!</p> <p>Welcome to my first mobile site.</p> <p>Try me on all of your mobile devices! You can use any<strong>valid HTML</strong> on this page</p> <img src="images/cable_car2.jpg" alt="Cable Car" /> <p style="text-align:center;">Powered by jQuery Mobile</p> <p><a href="#page3" data-role="button">Go to Third Page</a> </p> </div> <footer data-role="footer"> <h1>Footer</h1> </footer> </section> <!-- end second page --> <!-- begin third page --> <section id="page3" data-role="page"> <header data-role="header"> <h1>jQuery Mobile</h1> </header> <div data-role="content" class="content"> <p>Third page!</p> <p>Welcome to my first mobile site.</p> <p>Try me on all of your mobile devices! You can use any<strong>valid HTML</strong> on this page</p> <img src="images/alcatraz.jpg" alt="alcatraz" /> <p style="text-align:center;">Powered by jQuery Mobile</p> <p><a href="#page1" data-role="button">Go back to First Page</a> </p> </div> <footer data-role="footer"> <h1>Footer</h1> </footer> </section> <!-- end third page --> </body> </html> ترجمة -وبتصرّف- للمقال jQuery Mobile Lesson 3 لصاحبه Andrew اقرأ أيضًا الدرس التالي: ربط صفحات خارجية وتنظيم المحتوى بنظام الشبكة وبناء محتوى قابل للطي الدرس السابق: التضمين، تهيئة الصفحة، التنقل بين الصفحات وأحداث التحميل
  10. إذا ذهبت سابقا لإجراء مقابلة في بناء ما، ستعرف أن مكتب الاستقبال لن يسمح لأي شخص بالدخول والتجوال. بدلا من ذلك، يتأكّد من الزوار في قائمة المقابلات للتأكد من أنهم من المفترض أن يكونوا هنالك، فالأشخاص الموجودين في القائمة البيضاء (كما تعرف بقائمة المقابلة) سيدخلون، وسيُمنع أي شخص آخر. موقع ووردبريس هو عمل تجاري، فلذلك لن يكون هنالك سبب لعدم تطبيق نفس المنطق على المكتب الرقمي. فوضع العناوين IP في القائمة البيضاء مشابه لمكتب الاستقبال، فهو يسمح للزوار المصرح بهم بالدخول وسيمنع أولئك الذين لا يفترض تواجدهم هناك. في هذا المقال، سأبدأ بتفسير العمليّة أكثر مع تفاصيل حول وضع العناوين في القائمة البيضاء، ثم سأريك كيف يمكنك تطبيق هذه التقنية بالضبط على موقع ووردبريس باستخدام ملف ‎.htaccess وبعض الطرق الأخرى. ما معنى وضع عناوين IP في القائمة البيضاء؟ هذه العملية هي عكس عملية الوضع في القائمة السوداء، فهي طريقة للتحكم بمن يستطيع (أو لا يستطيع) الوصول إلى موقعك، ويمكن أن يكون هذا على كامل موقعك أو جزء معين فقط (مثل لوحة تحكم wp-admin). على الرغم من أن كل من وضع في القائمة البيضاء أو السوداء يتحكمان في الوصول، إلا أنهم يفعلان ذلك بطرق معاكسة تمامًا: • - الوضع في القائمة البيضاء (Whitelistening): سيخبر هذا خادمك بحظر الوصول للجميع ما عدا لعناوين IP معينة. • - وضع في القائمة السوداء (Blacklisting): سيخبر هذا خادمك بالسماح الوصول للجميع باستثناء عناوين IP معينة. وضع في القائمة السوداء جيّد للتعامل مع بعض الأشرار في حين أن وضع في قائمة البيضاء مقيّد أكثر لقفل إمكانية الوصول للمستخدمين غير المصرّح بهم. ما هي فوائد الإدراج عناوين IP في القائمة البيضاء؟ يمكن أن يكون وضع العناوين في القائمة البيضاء مفيدًا في حالتين رئيسيّتين: تعزيز الأمن للمواقع الحساسة مثل لوحة التحكم. المساعدة في تقييد الدخول إلى موقعك. من الناحية الأمنيّة، تسمح لك عملية الوضع في القائمة البيضاء بمنح حق الوصول إلى المناطق الحرجة والحساسة فقط من موقع ووردبريس (مثل wp-admin) إلى عناوين IP المصرح بها، لذا أي زائر غير مدرج في القائمة البيضاء لا يمكنه الدخول. بالإضافة إلى ذلك، سيكون ذلك مفيدًا أيضا عندما تعمل على تطوير الموقع، فعلى سبيل المثال، إذا كنت مستعدًا لإطلاق موقعك الجديد، فقد لا ترغب بأن يتمكن الناس من الوصول إلى موقعك حتى تكون مستعدًا. من خلال إدراج عناوين IP في القائمة البيضاء، يمكنك أنت والمستخدمين المصرح بهم رؤية موقعك الفعلي، لكن لن يتمكن أي شخص آخر من زيارته حتى تكون مستعدًا لإطلاقه. سلبيات محتملة لاستخدام تقييد الوصول إلى موقعك عن طريق عناوين IP توجد بعض الأشياء السلبيّة لاستخدام تقييد الوصول إلى موقعك، إذا كنت: • - تملك عنوان IP منزلي يتغيّر كثيرا. العمل من أماكن مختلفة. تحتاج إلى إعطاء إمكانية الوصول إلى أشخاص آخرين باستمرار. فستنّزعج قليلا في عدد المرات التي تحتاج فيها إلى تحديث قائمة البيضاء لعناوين IP. إذا كانت تنطبق عليك هذه الحالات، فسترغب في البحث عن طريقة أخرى (مثل استخدام الملف ‎.htpasswd). لكن إذا أردت الاستمرار في إدراج عناوين IP في القائمة البيضاء، فإليك ما سنقوم بعمله. كيف تقيد الوصول إلى موقع ووردبريس الخاص بك عن طريق إدراج العناوين في القائمة البيضاء بالنسبة لمعظم المستخدمين، الطريقة الأولى في هذه القائمة هي الأفضل والأكثر مرونة، لكن سنضع طريقتين إضافيتين التي تنطبق على حالات خاصة. 1- كيف تدرج عناوين IP في القائمة البيضاء مع ملف ‎.htaccess في أباتشي معظم استضافات ووردبريس تستخدم خادم ويب اباتشي الشهير والذي يعني أنه يمكنك إدراج العناوين إلى القائمة البيضاء إلى كامل أو جزء من موقع ووردبريس الخاص بك عن طريق استخدام ملف ‎.htaccess. إن ملف ‎.htaccess هو ملف إعدادات أساسي يمكنك من خلاله تغيير كيفية عملي اباتشي على مجلد معين، فعلى سبيل المثال، يمكنه بالإضافة إلى مساعدتك على إدراج العناوين في القائمة البيضاء، استخدامه لإعداد عمليات إعادة التوجيه أيضا. للوصول إلى ملف ‎.htaccess يمكنك إما: الاتصال بموقعك عن طريق FTP والبحث عنه في المجلد الجذر (root folder). استخدام أداة File Manager الخاصة بـ cPanel (إذا كانت استضافتك تستخدم cPanel). إليك ما يجب أن يبدو عليه عند الاتصال عبر FTP: وهذا ما سيبدو عليه عندما تستخدم cPanel File Manager: قبل أن تبدأ في التعديل على ملف ‎.htaccess، من المهم أن تنشئ نسخة احتياطيّة من الملف ‎.htaccess الحالي، وبهذه الطريقة، ستحصل على نسخة نظيفة في حالة أفسدت شيئًا ما. بعد وضع النسخة الاحتياطيّة في مكانٍ آمنٍ، يمكنك إدخال هذه المقتطفات من الشيفرات البرمجية، بناءً على مدى رغبتك في تقييد الوصول: للتحكم في الوصول إلى كامل موقع ووردبريس، ادخل مقتطف الشيفرة البرمجية التالي: order deny,allow deny from all allow from 123.123.123.123 تأكد من استبدال عنوان IP في المقال بعنوان IP الحالي (يمكنك الحصول على عنوان IP الخاص بك من هنا). إذا أردت وضع أكثر من عنوان IP في القائمة البيضاء، أضف سطر allow from آخر كالتالي: order deny,allow deny from all allow from 123.123.123.123 allow from 234.234.234.234 لحظر الوصول إلى صفحات wp-admin و wp-login.php فقط، ادخل مقتطف الشيفرة البرمجيّة التالي: RewriteEngine on RewriteCond %{REQUEST_URI} ^(.*)?wp-login\.php(.*)$ [OR] RewriteCond %{REQUEST_URI} ^(.*)?wp-admin$ RewriteCond %{REMOTE_ADDR} !^123\.123\.123\.123$ RewriteRule ^(.*)$ - [R=403,L] تأكد من استبدال عنوان IP في المثال مع العنوان الخاص بك، لكن اترك الخطوط المائلة، استبدل فقط أرقام “123”. كما في المثال السابق، يمكنك وضع عدة عناوين IP في القائمة البيضاء عن طريق نسخ السطر الذي يحتوي على عنوان IP كالتالي: RewriteEngine on RewriteCond %{REQUEST_URI} ^(.*)?wp-login\.php(.*)$ [OR] RewriteCond %{REQUEST_URI} ^(.*)?wp-admin$ RewriteCond %{REMOTE_ADDR} !^123\.123\.123\.123$ RewriteCond %{REMOTE_ADDR} !^234\.234\.234\.234$ RewriteRule ^(.*)$ - [R=403,L] تأكد من حفظ التغييرات وانتهينا. 2- كيف تدرج عناوين IP عن طريق إضافة ووردبريس إذا لم ترغب في تعديل ملف ‎.htaccess، يمكنك استخدام الإضافات لمساعدتك على وضع عناوين IP في القائمة البيضاء لصفحة تسجيل الدخول فقط. أفضل إضافة وجدتُها هي إضافة Cerber Security & Antispam المجانية، فهي لا تمنع تماما العناوين غير المصرح بها، لكنها تساعدك على قفل صفحة تسجيل الدخول بشكل صارم لجميع عناوين IP التي لم تدّرج في القائمة البيضاء. هذه الإضافة موجودة في مستودعات WordPress.org لذلك يمكنك تثبيتها وتفعيلها من لوحة تحكم ووردبريس، وبمجرّد تنشيطها، يمكنك إعداد الإضافة عن طريق الذهاب إلى علامة التبويب WP Cerber في لوحة تحكم ووردبريس. ابحث عن علامة التبويب Access Lists حتى تبدأ بإدراج عناوين IP من التحكم الصارم لتسجيل الدخول الخاص بـ WP Cerber: 3- كيف تدرج عناوين IP في القائمة البيضاء على خوادم ويب Nginx في حين أن معظم استضافات ووردبريس تستخدم خادم ويب أباتشي، إلا أن الكثير من موفري خدمة الاستضافة المميّزة يستخدمون أو على الأقل يقدمون خادم ويب Nginx بدلا من ذلك. لا ينصح Nginx باستخدام ‎.htaccess وهو خيار وضع الإعدادات في ملف واحد. إذا كانت استضافتك تستخدم Nginx، فمن الأفضل أن تطِلع على توثيق الاستضافة أو التحدّث مع فريق الدعم للاستضافة. حاولت عمل تجربة لهذا المقال، لكن لم يسمح لي المستضيف بالوصول إلى الملف الضروري، لذلك هنالك فرصة جيدة لمضيفك أيضا. الخاتمة يعدّ وضع عناوين IP في القائمة البيضاء وسيلة فعّالة للتحكم في الوصول إلى جميع أجزاء موقعك أو جزء منه. إذا افترضنا أن استضافتك تستخدم خادم ويب اباتشي (والذي تقوم به أغلب استضافات ووردبريس)، أفضل طريقة لإدراج عنوان IP في القائمة البيضاء هي عن طريق ملف ‎.htaccess. إذا كنت مهتمٍا فقط بغلق صفحة تسجيل الدخول عن طريق إدراجها في قائمة البيضاء، يمكنك إيجاد إضافات لمساعدتك على ذلك، على الرغم من أنها لا تعطيك تحكم كامل كملف ‎.htaccess. وفي النهاية، إذا كانت استضافتك تستخدم خادم ويب Nginx، ستحتاج في التواصل معهم وسؤالهم عن أفضل طريقة لإدراج عناوين IP في القائمة البيضاء. ترجمة -وبتصرّف- للمقال How To Whitelist IP Addresses in WordPress For Dummies لصاحبه Colin Newcomer
  11. نواصل اليوم دروسنا حول jQuery Mobile، في هذا الدرس، سنطّلع على أمثلة تهيئة، وإنشاء صفحات، ومعاجلات الحدث (event handlers)، وتنقلات الصفحة وغيرها. هذا الدرس جزء من سلسلة دروس تشرح jQuery Mobile: الدرس الأول: البداية، بناء وتقديم محتوى الدرس الثاني: التضمين، تهيئة الصفحة، التنقل بين الصفحات وأحداث التحميل الدرس الثالث: اتجاه الصفحة وأحداثها الدرس الرابع: ربط صفحات خارجية وتنظيم المحتوى بنظام الشبكة وبناء محتوى قابل للطي الدرس الخامس: الأيقونات والأزرار وإنشاء تنسيقات مخصصة الدرس السادس: إنشاء القوائم وتنسيقها وإنشاء نماذج البحث وتسجيل الدخول تضمين jQuery Mobile في موقعك من السهل إضافة إطار jQuery إلى موقعك كسهولة إضافة أي ملف جافا سكربت خارجي. <!DOCTYPE html> <html> <head> <title>jQuery Mobile on Script Tutorials</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" /> <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script> <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"> </script> </head> <body> <p>Site contents will be here</p> </body> </html> إنشاء صفحة بسيطة باستخدام jQuery Mobile تحدثنا بالفعل على الشيفرة البرمجية لبناء هيكل بسيط لموقع ويب للهواتف، لكننا لا يشبه مواقع الويب للهواتف، لننشئ إذا موقع يتكون من صفحة واحدة وزر حتى نفهم طريقة عمل jQuery Mobile. يعين jQuery Mobile الصفحات باستخدام الخاصية data-role. في ما وراء الكواليس، يحدد jQuery Mobile العناصر المبنية على هذه الخاصية ويعززها بشكل تدريجي بإضافة: أصناف CSS، أي ترميز لازم، إدارة للأحداث. تبدو هذه وكأنها طريقة معقدة للتعامل مع الأشياء، لماذا لا يكون لدينا صفحات عادية مرتبطة كالعادة؟ لكننا في هذا الدرس سنغطي عدة مميزات هامة لـ jQuery Mobile: تنقلات الصفحة من خلال التعامل مع الصفحات كمناطق محتوى منفصلة في ملف واحد، يمكن لـ jQuery Mobile إنشاء تنقلات سلسة للصفحات، مما يؤدي إلى مظهر مشابه للتطبيقات. إدارة التصفح يمكن لـ jQuery Mobile التعامل تلقائيًا مع تصفح الصفحة عن طريق توفير مميزات مثل أزرار العودة والربط العميق. الكفاءة لن يحتاج المتصفح إلى الوصول إلى الشبكة مرارًا وتكرارًا بما أن جميع الموارد موجودة في ملف واحد، كما هو الحال مع الملفات الفردية الأصغر حجمًا. سيساعد هذا على تخفيف بطء التطبيق واستنزاف بطارية الهاتف، لكن من جهة أخرى، سيكون وقت تحميل أطول لصفحات HTML الكبيرة التي تحتوي على العديد من العروض (views) الفردية لصفحة jQuery Mobile. ومع ذلك، بمجرد تحميل الملف، فإن السلوك سيصبح أسرع ولن يعتمد بالضرورة على الوصول إلى الشبكة. <!DOCTYPE html> <html> <head> <title>Script-tutorial: jQuery Mobile</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" /> <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script> <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"> </script> </head> <body> <div data-role="page"> <div data-role="header"><h1>Single Page Site</h1></div> <div data-role="content"> <p>Look at the button!</p> <a href="https://www.script-tutorials.com" data-role="button">I am a button</a> </div> </div> </body> </html> المثال 1: إنشاء صفحة بسيطة باستخدام jQuery mobile <!DOCTYPE html> <html> <head> <title>Script-tutorial: jQuery Mobile</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" /> <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script> <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"> </script> </head> <body> <div data-role="page"> <div data-role="header"><h1>Single Page Site</h1></div> <div data-role="content"> <p>Look at the button!</p> <a href="https://www.script-tutorials.com" data-role="button">I am a button</a> </div> </div> </body> </html> صفحة بسيطة مع زر واحد مرتبط إلى صفحة الحوار (dialog page) المثال 2: إنشاء صفحة بسيطة باستخدام jQuery Mobile مع زر يعمل وصفحة ثانية <!DOCTYPE html> <html> <head> <title>Script-tutorials: jQuery Mobile</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" /> <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script> <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"> </script> </head> <body> <div data-role="page"> <div data-role="header"><h1>Single Page Site</h1></div> <div data-role="content"> <p>Look at the button!</p> <a href="#dpop" data-role="button" data-rel="dialog">I am a button</a> </div> </div> <div data-role="page" id="dpop" data-theme="d"> <div data-role="header"><h1>Clicked!</h1></div> <div data-role="content"> <p>clicked content!</p> <a href="#" data-rel="back" data-role="button">Go back</a> </div> </div> </body> </html> القسم 2.2: إطار عمل jQuery Mobile حدث تهيئة الهاتف يستخدم إطار عمل jQuery دالة ‎$(document).ready()‎ للتحايل على مشاكل التلاعب والتحميل عن طريق إعطائك صلاحية الوصول إلى دوالك في أقرب وقت. في حين أن هذا الأمر رائع للمواقع المتكونة من صفحة واحدة، لكنه سيصبح مشكلة صغيرة لإطار عمل jQuery Mobile. يستخدم jQuery Mobile طلبيات AJAX لتحميل محتويات كل صفحة بدلا من إعادة تحميل بنية DOM كاملة. تعمل دالة ‎$(document).ready()‎ مرة واحدة عند تحميل الصفحة، وليس عن طريق نداء AJAX، في jQuery Mobile، لا تعمل دالة ‎$(document).ready()‎ مرة واحدة في الصفحة، لكن مرة في الموقع ما لم يطلب المستخدم تحديث الصفحة، وهذا يعني أن بعض الإعدادات الافتراضية التي يجب تعيينها عن طريق jQuery Mobile لا يمكن تعيينها في دالة ‎$(document).ready()‎ لأنها لن تُطبّق في الصفحات الأخرى المتضمنة عن طريق AJAX. الحل هو تعيين وتغيير هذه الافتراضات باستخدام حدث mobileinit لأنه يعمل قبل دالة ‎$(document).ready()‎. يجب عليك تضمين إطار عمل jQuery لاستخدام حدثmobileinit ومن ثم إما عن طريق تضمين مباشر أو تضمين خارجي لملف جافا سكربت يحتوي على حدث الربط لحدث mobileinit وفي النهاية تضمين jQuery Mobile. مثال 3: تضمين jQuery، سكربت mobileinit مضمن و jQuery Mobile <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script> <script type="text/javascript"> $(document).on("mobileinit", function() { $.extend( $.mobile , { pageLoadErrorMessage: 'Either the page cannot be found or it cannot be loaded.' }); }); </script> <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script> تهيئة صفحة في jQuery Mobile يجب عليك اتباع نهج أقل حيوية (dynamic) وأكثر تخطيط لاستخدام حدث pageinit على صفحتك، فتوجد عدة طرق لإرفاق حدث pageinit في شيفرتك البرمجية ففي نسخ jQuery Mobile قبل 1.1، ستستخدم jQuery 1.6.4 وهذا يعني أنه يجب عليك استخدام دالة ‎.bind()‎ بدلا من دالة ‎.on()‎،وعند استخدام الإصدار 1.1 وما بعده من jQuery Mobile ستستخدم دالة ‎.on()‎ لربط الحدث. دالة ‎.on()‎ الموجودة في jQuery 1.7 هي توحيد لعدة دوال تُستخدم في ربط الأحداث، فبدلا من القلق على استخدام ‎.bind()‎ أو ‎.live()‎ أو ‎.delegate()‎ يمكنك الآن استخدام دالة ‎.on()‎ لإيجاد الأحداث، يمكنك معرفة المزيد من المعومات حول هذه الدالة عن طريق زيارة التوثيق. إذا كنت تستخدم إصدار jQuery Mobile قبل 1.1، تجنب استخدام التابع ‎.on()‎، ويجب عليك بدلا من ذلك استخدام دالة ‎.delegate()‎ أو ‎.live()‎. المثال 4: استخدام حدث سكربت pageinit و mobileinit بدلا من ‎$(document).ready()‎ ستظهر لك الصورة في الأعلى إذا كانت صفحة multipage_two.html غير متوفرة في رابط المباشر للمجلد. <!DOCTYPE html> <html> <head> <title>Script-Tutorials jQuery Mobile</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" /> <script type="text/javascript"> $(document).on("mobileinit", function() { $.extend( $.mobile , { pageLoadErrorMessage: 'Either the page cannot be found or it cannot be loaded.' }); }); //THE TIED EVENT OF THE MULTIPAGE_TWO.HTML BEGINS $(document).on("pageinit","#pageinit2", function() { alert("pageinit is bound!"); }); //THE TIED EVENT OF THE MULTIPAGE_TWO.HTML ENDS </script> </head> <body> <div data-role="page"> <div data-role="header"><h1>pageinit event example</h1></div> <div data-role="content"> <p>The button below will use AJAX to load another page and trigger a bound event</p> <a href="multipage_two.html" data-role="button">Click to open a new page</a> </div> </div> </body> </html> السكربت أدناه يحتوي على حدث مرتبط في السكربت أعلاه لـ pageinit.html، وهذا سيُطلق (Trigger) تحميل الصفحة مباشرة من ذلك الملف. هذه multipage_two.html <!DOCTYPE html> <html> <head> <title>Script-tutorials: jQuery mobile</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0-rc.1/jquery.mobile-1.1.0-rc.1.min.css"/> <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script> <script src="http://code.jquery.com/mobile/1.1.0-rc.1/jquery.mobile-1.1.0-rc.1.min.js"> </script> </head> <body> <div data-role="page" id="pageinit2"> <div data-role="header"><h1>pageinit event example </h1></div> <div data-role="content"> <p>Fantastic! I am a new page and was loaded through AJAX.</p> <a href="pageinit.html" data-role="button" data-rel="back">Amazing, now take me back</a> </div> </div> </body> </html> <img src="https://www.script-tutorials.com/demos/511/img6.png" data-lazy-src="https://www.script-tutorials.com/demos/511/img6.png" class=" lazyloaded"> <!DOCTYPE html> <html> <head> <title>Script-Tutorials jQuery Mobile</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" /> <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script> <script type="text/javascript"> $(document).on("mobileinit", function() { $.extend( $.mobile , { pageLoadErrorMessage: 'Either the page cannot be found or it cannot be loaded.' }); }); $(document).on("pageinit","#pageinit2", function() { alert("pageinit is bound!"); }); </script> <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script> </head> <body> <div data-role="page"> <div data-role="header"><h1>pageinit event example</h1></div> <div data-role="content"> <p>The button below will use AJAX to load another page and trigger a bound event</p> <a href="multipage_two.html" data-role="button">Click to open a new page</a> </div> </div> </body> </html> هذه هي الصفحة multipage_two.html: التنقل بين الصفحات تتكون العملية من صفحتين: صفحة "من” وصفحة "إلى”، هذه التنقلات تغيّر الصفحة من الصفحة الحالية (fromPage) إلى صفحة جديدة (toPage). إخفاء الصفحة وأحداث الظهور يفرق jQuery Mobile بين أحداث صفحة التحويل وأحداث إظهار وإخفاء الصفحة بسبب طبيعته غير المتزامنة، تحدث أحداث تحميل الصفحة عند تحميل الملف إلى المتصفح بطرية متزامنة، وعند تحميل الصفحة بهذه الطريقة، سيصبح التابع jQuery(document).ready()‎ متاحًا للاستعمال وسيشغل jQuery Mobile أحداث التهيئة الأخرى كذلك. كما رأينا، قد يحتوي ملف صفحة HTML الواحدة على عدة عروض (views) لـ jQuery Mobile، ويمكن للمستخدم الانتقال بين مناظر هذه الصفحة عدة مرات. هذه الصفحة لا تطلق أحداث تحميل الصفحة، وبدلا من ذلك، يوفر jQuery Mobile مجموعة من الأحداث التي تعمل في كل مرة يحدث فيها انتقال للصفحة، وكل واحدة من هذه الأحداث توفر مرجع إلى الحدث وكائنات واجهة المستخدم: pagebeforehide: ينطلق هذا الحدث في الصفحة التي يُنتقل منها قبل بدء عملية الانتقال. ستكون ui.nextPage الصفحة التي يُنتقل إليها أو كائن jQuery فارغ إذا لم يكن هناك أي صفحة. Pagebeforeshow: ينطلق هذا الحدث في الصفحة التي يُنتقل إليها قبل بدء عملية الانتقال. ستكون ui.prevPage الصفحة التي يُنتقل منها أو كائن jQuery فارغ إذا لم يكن هناك أي صفحة. Pagehide: ينطلق هذا الحدث في الصفحة التي يُنتقل منها بعد انتهاء عملية الانتقال. سيكون ui.nextPage كائن jQuery للصفحة التي يُنتقل إليها أو كائن jQuery فارغ إذا لم يكن هناك أي صفحة. Pageshow: ينطلق هذا الحدث في الصفحة التي يُنتقل إليها بعد انتهاء عملية الانتقال. سيحتوي ui.prevPage كائن jQuery للصفحة التي يُنتقل منها أو كائن jQuery فارغ إذا لم يكن هناك أي صفحة. توفر هذه الأحداث الأربعة نظير لنداء jQuery(document).ready()‎ لمناظر صفحة التطبيق. لاستخدام هذه الأحداث، ارفق مستمع الحدث (event listeners) إلى الصفحة المناسبة باستخدام jQuery.bind()‎، أو jQuery.live()‎، أو jQuery.delegate()‎. jQuery.bind()‎، و jQuery.live()‎، و jQuery.delegate()‎ هي توابع يملكها jQuery لربط المعالجات (handlers) إلى مستمعي الأحداث. للمزيد من التفاصيل، راجع توثيق jQuery، وهنا نستخدم jQuery.bind()‎: <script> $("#page1").bind("pagehide", function(event, ui) { var strAlert = ""; for (var thing in event) { strAlert += thing + " : " + event[thing] + "\n"; } alert(strAlert); }); </script> بالنسبة للصفحات المتكونة من نفس الملف، سيكون jQuery.bind()‎ كافيا. بالنسبة للصفحات التي ستُحمّل بشكل غير متزامن عن طريق jQuery Mobile، استخدم jQuery.delegate()‎ أو jQuery.live()‎. المثال 5: حدث pagebeforehide <!DOCTYPE html> <html> <head> <title>Script-tutorials: pagebeforehide Event</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.css"> <script src="http://code.jquery.com/jquery-1.11.3.min.js"></script> <script src="http://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.js"></script> <script> $(document).on("pagebeforehide","#pagetwo",function(){ alert("pagebeforehide event fired - pagetwo is about to be hidden"); }); </script> </head> <body> <div data-role="page" id="pageone"> <div data-role="header"><h1>pagebeforehide Event</h1></div> <div data-role="main" class="ui-content"> <p>Page One</p> <a href="#pagetwo" data-role="button">Go to Page Two</a> </div> <div data-role="footer"> <h1>Header</h1> </div> </div> <div data-role="page" id="pagetwo"> <div data-role="header"><h1>pagebeforehide Event</h1></div> <div data-role="main" class="ui-content"> <p>Page Two</p> <a href="#pageone" data-role="button">Go to Page One</a> </div> <div data-role="footer"> <h1>Footer</h1> </div> </div> </body> </html> المثال 6: حدث pagebeforeshow <!DOCTYPE html> <html> <head> <title>Script-tutorials: pagebeforehide Event</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.css"> <script src="http://code.jquery.com/jquery-1.11.3.min.js"></script> <script> $(document).on("pagebeforeshow","#pagetwo",function(){ // When entering pagetwo alert("pagetwo is about to be shown"); }); $(document).on("pageshow","#pagetwo",function(){ // When entering pagetwo alert("pagetwo is now shown"); }); $(document).on("pagebeforehide","#pagetwo",function(){ // When leaving pagetwo alert("pagetwo is about to be hidden"); }); $(document).on("pagehide","#pagetwo",function(){ // When leaving pagetwo alert("pagetwo is now hidden"); }); </script> <script src="http://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.js"></script> </head> <body> <div data-role="page" id="pageone"> <div data-role="header"><h1>pagebeforehide Event</h1></div> <div data-role="main" class="ui-content"> <p>Page One</p> <a href="#pagetwo" data-role="button">Go to Page Two</a> </div> <div data-role="footer"> <h1>Footer 1</h1> </div> </div> <div data-role="page" id="pagetwo"> <div data-role="header"><h1>pagebeforehide Event</h1></div> <div data-role="main" class="ui-content"> <p>Page Two</p> <a href="#pageone" data-role="button">Go to Page One</a> </div> <div data-role="footer"> <h1>Footer 2</h1> </div> </div> </body> </html> أحداث تحميل JQUERY MOBILE أحداث تحميل الصفحة للصفحات الخارجية. كلما تُحمّل صفحة خارجية في DOM، سيعمل حدثين، الأول هو pagecontainerbeforeload والثاني إما pagecontainerload (نجاح) أو pagecontainerloadfailed (فشل). ويرد في الجدول أدناه شرح لهذه الأحداث: الحدث الوصف pagecontainerbeforeload تشتغل قبل أي طلب لتحميل صفحة. pagecontainerload تشتغل بعد تحميل الصفحة بنجاح وتُدرج في DOM. pagecontainerload تشتغل إذا فشل طلب تحميل الصفحة، افتراضيًا ستُظهر رسالة “Error Loading Page”. تشتغل إذا فشل طلب تحميل الصفحة، افتراضيًا ستُظهر رسالة “Error Loading Page”. ستجد في الأسفل الشيفرة البرمجية لملف main.html المثال 7: حدث تحميل الصفحة عند وجود زر لتحميل الصفحة الخارجية، ستظهر هذه الصورة في المتصفح <!DOCTYPE html> <html> <head> <title>Script-tutorials: pagebeforehide Event</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.css"> <script src="http://code.jquery.com/jquery-1.11.3.min.js"></script> <script> $(document).on("pagecontainerload",function(event,data){ alert("pagecontainerload event fired!\nURL: " + data.url); }); $(document).on("pagecontainerloadfailed",function(event,data){ alert("Sorry, requested page does not exist."); }); </script> <script src="http://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.js"></script> </head> <body> <div data-role="page" id="pageone"> <div data-role="header"><h1>Load Events</h1></div> <div data-role="main" class="ui-content"> <p>Content data loaded or faile to load</p> <a href="pageexist.html" data-role="button">External Page Exist</a> <a href="page_notexist.html" data-role="button">No Page Exist</a> </div> <div data-role="footer"> <h1>Footer</h1> </div> </div> </body> </html> ترجمة -وبتصرّف- للمقال jQuery Mobile Lesson 2 لصاحبه Andrew اقرأ أيضًا الدرس التالي: اتجاه الصفحة وأحداثها الدرس السابق: البداية، بناء وتقديم محتوى
  12. نشعر بالأمان أكثر كلما اكتشفنا طرقًا جديدةً لزيادة أمن مواقع ووردبريس، وهذا الأمر جيّد وسيّء في نفس الوقت، فهو جيّد لأنه يعني أننا نثق بالأدوات والخدمات التي استثمرنا فيها لتأمين ووردبريس، وهي سيئة لأننا نخلط بين زيادة أمن المواقع وعقليّة "ضعها وانسها". بصراحة: يحاول القراصنة اختراق موقعك، فإذا كنت تعتقد أن موقعك صغير أو جديد ليكسب انتباه القراصنة، ففكّر من جديد، إذ يوجد 90978 هجوم أمني يحدث كل دقيقة من كل يوم، ولا يفكر القراصنة في حجم الموقع أو العمل عندما يهاجمونه. يعلم القراصنة أن لووردبريس نقاط ضعف كثيرة، لذلك إذا أردت زيادة أمن موقعك فيجب عليك التفكير كمخترق، حدد نقاط الضعف في موقعك وفكر في الطرق المختلفة التي يمكنك من خلالها استغلال هذه النقاط، وعندها فقط ستكون قادر على درء الهجمات. أين تقع أضعف البقع في موقع ووردبريس؟ ربما من الأشياء الأكثر رعبًا أن القراصنة لا يبحثون بشكل خاص على موقعك (خاصة إذا كان جديد أو صغير)، فالعديد من القراصنة يبحثون عن نقاط الضعف باستخدام bots، فالأخيرة تكشف عن المداخل للقراصنة، لذلك فإن أي موقع ووردبريس يمكن أن يكون الضحيّة. لذا من المهم التعرّف على أشهر نقاط الضعف في ووردبريس لإبقاء القراصنة بعيدين عن موقعك. كلمات المرور أي بقعة في الواجهة الخلفية (backend) أو الأماميّة (frontend) من موقعك التي تطلب اسم مستخدم وكلمة مرور هي من الأماكن الرئيسية التي يستهدفها القراصنة، ومنها منطقة تسجيل الدخول الرئيسية لووردبريس: لوحات التعليقات: حسابات التجارة الإلكترونية أو بوابات الدفع: يعرف القراصنة أن المستخدمين لا يهتمون دائمًا بإنشاء كلمات مرور قويّة لكل حساب يملكونه على الإنترنت (يتعارض هذا مع أساسيات أمن كلمة المرور 101). وسيكون هذا أحد الأهداف الأولى على موقع ووردبريس الخاص بك. التعليقات ليست التعليقات مشكلة أمنية بسبب عنصر تسجيل الدخول (إذا كان هنالك واحد)، فيمكن للتعليقات أن تكون مشكلة بسبب الرسائل غير المرغوب فيها، ولهذا فإن بعض الناس يختارون تعطيل التعليقات بالكامل في ووردبريس. وإليك مثال لتعليقات من عملاء سيئين. قد لا يؤدي هذا الرابط إلى شيء ضار، لكنه بالتأكيد لا ينتمي إلى هذه المجموعة من التعليقات. نماذج الاتصال نماذج الاتصال، أو نماذج الاشتراك، أو نماذج الدفع أو أي جزء من الموقع يطلب من المستخدمين إدخال تفاصيل هو مكان واضح يستهدفه القراصنة. بالطبع، يمكنك اختراق الموقع ومن ثم الاستيلاء على البيانات الحساسة التي أُدخلت إلى هذه الحقول، وهنالك طريقة يمكن للقراصنة من خلالها سرقة البيانات من خلال مراقبة نقرات المستخدمين إما عن طريق لوحات المفاتيح اللاسلكية أو عن طريق استخدام البرامج الضارة التي تُثبّت على أجهزة الحاسوب الخاصة بهم. قاعدة بيانات ووردبريس في حين أنه من الرائع أن ووردبريس قد بسّط تسمية الملفات وهياكل قاعدة البيانات في جميع المواقع، لكنه أحدث أيضًا مشكلة كبيرة إذ أن كل شخص منا (بما في ذلك المخترقين) يعرفون أن البادئة “wp-‎” تُستخدم لتسمية كل شيء تقريبًا، وهذا سيترك قاعدة بيانات ووردبريس مكشوفة بشكل كامل وعرضة للهجوم إذا لم يتغير ذلك. نواة ووردبريس هل تعلم أن 73% من نسخ ووردبريس القديمة تحتوي على نقاط ضعف داخلها؟ على الرغم من أنه ليس من مسؤوليتكم إدارة نواة ووردبريس (WordPress core)، فمن المؤكد أن من مسؤوليتكم أن تثبتوا أي تحديث جديد لووردبريس، فيجتهد الفريق الأمني لووردبريس دائما لجعل النواة محدّثة، ومن المهم أن يفعل مطورو ووردبريس الأمر نفسه حتى لا تبقى نقاط الضعف هذه في مواقعهم. إضافات ووردبريس إن الإضافات أكثر عرضة للانتهاكات الأمنية من نواة ووردبريس، في الحقيقة، تتحمل إضافات ووردبريس 50% من الهجمات الأمنية على مواقع ووردبريس. بالطبع، لا ينبغي لهذا أن يجعلك تخاف من استخدام إضافات ووردبريس، فهي جزء أساسي من العمل الذي تقوم به لإنشاء مواقع تفاعليّة وجذابة لجمهورنا، ومع ذلك، فهذا يعني أنك بحاجة إلى إيلاء اهتمام أكبر لما يحدث مع مجموعة الإضافات الحالية كما يجب أن تبقي عينيك وأذنّيك مفتوحة عند مراجعة إضافات جديدة لموقعك. هنالك بشكل عام طريقتان يمكن من خلالها أن تضعف الإضافات أمن موقعك: عند تحديثها من قبل المطور، لكنك لا تحدّثها في موقعك (أو عدم فعل ذلك في الوقت المناسب). عند إضافة إضافة ووردبريس مزيّفة إلى موقعك دون قصد. لذلك، تأكد من اهتمامك بهذه النقاط. قوالب ووردبريس الشيء نفسه ينطبق على قوالب ووردبريس، على الرغم من أنه لا داعي للقلق حول استخدام قالب مزيّف، فهي مجرد مسألة إصدار التحديثات من المطور في الوقت المناسب. خدمة استضافة المواقع للأسف، ليست كل شركات استضافة المواقع متشابهة وهذا يمكن أن يؤثر غالبًا على مستوى أمن الخادم، وبطبيعة الحال، يجب عليك التأكد من هذه النقاط عند اختيار خطة استضافة مواقع: التشفير وجدار حماية جانب الخادم. نوع خادم الويب NGINX أو Apache. برامج مضادات الفايروسات والبرامج الضارة. أنظمة الأمن في الموقع. توفر شهادات SSL و CDN. يوجد أيضا خطر الإصابة عن طريق عدة مواقع عند وجود عدة نطاقات تتشارك في نفس المساحة على الخادم، فإذا كانت هذه هي حالتك، فقد تحتاج إلى اتخاذ احتياطات أمنية إضافيّة على مستوى الخادم. ماذا يريد المخترقين من موقعك؟ إذا فكرت في "موقعي صغير/جديد/محلي، فماذا يريد المخترقون منه؟” فلقد حان الوقت لتغيّر رأيك، فالقراصنة لا يريدون فقط تدمير الشركات الكبيرة، انهم ببساطة يبحثون عن أي ضعف يمكن استغلاله. لذا، في المرة القادمة التي تفكر فيها بـ "ليس لديّ أي شيء يُريدونه”، فكّر في الفرص التالية التي قد يستفيدون منها: 1- حقن محتوى خبيث في بعض الحالات، يريد القراصنة ببساطة إضافة محتوى خبيث أو شيفرات برمجية على الواجهة الأماميّة من موقع ووردبريس مع أمل أن يضغط زوارك على الروابط الخاطئة، ويمكن أن يحدث هذا عن طريق التعليقات غير المرغوب فيها، أو عن طريق اختراق البريد الإلكتروني لموقعك وإرسال رسائل غير مرغوب فيها لمتابعينك، أو من خلال إرسالات (submissions) المحتوى الحالي. كمثال على الأخيرة، الق نظرة على نقطة ضعف إضافة NextGEN Gallery، فعن طريقها، استطاع المخترقين تعديل شيفرة PHP الخاصة بالموقع ومن ثم مهاجمة الموقع عن طريق هذه الإضافة. 2- نشر الفايروسات من الطرق الأخرى التي يستخدمها المخترقين لإرهاب زوارك هي عن طريق استخدام موقع ووردبريس الخاص بك لنشر الفايروسات والبرامج الضارة، ويمكنهم إجراء ذلك باستخدام شيفرة برمجية ضارة كتبوها في الواجهة الخلفية أو مع الملفات المرفوعة للتحميل في الواجهة الأماميّة وعندما يتفاعل الزوار معهم، يسرق المخترقون معلومات الزائرين أو يستخدمون حواسيبهم لنشر الفايروسات على مواقع ويب أخرى. إن إضافة BlogVault backup هي مثال جيّد على هذا، فمن خلال هذا الهجوم، استطاع المخترقون على إصابة مواقع ووردبريس التي تستعمل هذه الإضافة ببرامج خبيثة. 3- سرقة المعلومات الشخصية للزائر هذه أهم واحد يقلق حولها الزوار ويجب أن تأمل أن لا تحدث على الإطلاق لأنها مكلفة للغاية، فأي خرق أمني سيُسيء للعمل التجاري، لكن في هذه الحالة، يجب عليك تعويض زوارك وعملاءك للمال والخصوصية التي تعرضت للخطر في الهجوم، ناهيك عن فقدان الثقة في علامتك التجاريّة. يمكن للمخترقين الحصول على هذه المعلومات بطرق مختلفة ويمكنهم الاستفادة منها كثيرًا، في بعض الأحيان لمكاسب ماليّة، لكن في أحيان أخرى مثل اختراق Ashley Madison حيث أنهم يحاولون تقديم بيان. 4- سرقة بيانات أعمال خاصة تعمل الشركات بجد للحفاظ على تفاصيل تتعلق بالشركة (وخاصةً فيما يتعلق بالأمور الماليّة وتفاصيل حساب العميل) تحت الأغطيّة، ولهذا السبب، من المهم للغاية عدم وصول هذه المعلومات إلى موقع أعمال المنافس. نقطة ضعف Heartbleed هي مثال حديث لهذا النوع من الهجوم وهو بسبب مشكلة في OpenSSL وهو شيء مصنوع لزيادة حماية المواقع، وبدلا من ذلك، ما فعله OpenSSL هو إرسال بيانات عمل حساسة إلى المخترقين عند إرسالهم طلبات وهمية إلى خوادم المواقع المصابة. 5- استضافة صفحات التصيد في خادمك يشير التصيّد في المواقع بشكل أساسي إلى إنشاء القراصنة لصفحة مزيفة على موقع ووردبريس لمحاولة جمع المعلومات من الزائرين الذين يرغبون في إعطائها. ويمكنهم القيام بذلك عن طريق تضمين نموذج اتصال في الصفحة وجمع البيانات بشكل مباشرة أو يمكنهم إعادة توجيه الزائرين إلى موقع آخر حيث ستُرفع هذه المعلومات. يقوم جوجل بإدراج 50000 موقع كل أسبوع في القائمة السوداء بسبب عمليات التصيّد. 6- استضافة صفحات شرعية في خادمك بعض القراصنة يبنون صفحات شرعيّة في مواقع ووردبريس من أجل تحسين SEO (تحسين محركات البحث) الخاص بهم، وتتحدث هذه الصفحات عن شركتهم الخاصة وروابط لهم من أجل تحسين من قوّة موقعهم في محركات البحث، أو قد يختارون تخطي الصفحة المقصودة ويستخدمون نهج أكثر دقة لتعزيز SEO الخاص بهم، في هذه الحالة، سيستخدمون نظام الروابط الخلفية (backlinks) من موقعك لمواقعهم. 7- حمل زائد على خادمك عندما قيام القراصنة بتحميل زائد على خادمك عن طريق أعداد كبيرة من الزيارات، وهذا ما يعرف بهجوم الحرمان من الخدمات (DdoS)، فسيتوقف موقعك عن العمل عندما يصلون إلى ذلك، وسيفوزون، ولماذا يفعلون ذلك؟ ما الذي يمكنهم الحصول عليه من إيقاف موقعك؟ حسنًا، ربما يحصلون على لذة الانتصار، أو بسبب ثأر شخصي ضد العلامة التجارية، أو ربما موقعك هو واحد من عدة ضحايا في هجوم واسع النطاق، أو ربما فعلوا ذلك من أجل المطالبة بفديّة. 8- سرقة عرض نطاق (Bandwidth) الموقع تحدثتُ سابقا كيف يمكن سرقة الصور من موقع ووردبريس الخاص بك بعلمك أو بدون علمك، وواحدة من هذه الطرق هي عن طريق الربط الساخن (hotlinking)، والذي يحول موقعك إلى استضافة لحركة مرور بيانات (traffic) المواقع الأخرى عن طريق روابط الصور. ومع ذلك، هنالك طرق أخرى يمكن من خلالها للقراصنة سرقة موارد خادمك لاستضافة أنشطتهم السيئة مثل تعدين البيتكوين وهجمات الحرمات من الخدمة وهذا بالضبط ما حدث في قضيّة اختراق Monero mining حيث أصبحت المواقع التي اخترقت "عبيدًا”، تُستخدم في أنشطة التعدين للقراصنة. 9- تخريب موقعك وبطبيعة الحال، هنالك تخريب المواقع، ففي أغلب الأحيان، يفعل المخترقون هذا لإنشاء هويّة لأنفسهم بينما يضرون في الوقت نفسه علامتك التجاريّة، ولقد حدثت هذه التشويهات في مجموعة كبيرة من مواقع ووردبريس، واستمرت في حدوث حتى بعد تحديث ووردبريس لأن المستخدمين فشلوا في التحديث في الوقت المناسب. الخاتمة لإنهاء هذا بملاحظات إيجابيّة، لنحاول التركيز على ما نعرفه: لا، فوردبريس ليس "غير قابل للقهر”. ولكن نعم، لدينا الوسائل لوضع دفاع جيّد ضد المتسللين إذا كنا نعرف إلى أين ننظر. كتذكير، هذا ما يمكنك القيام به: عمل نسخة احتياطية من موقعك بانتظام. تأمين موقعك على كافة المستويات: الخادم، والنواة، والإضافات، والقوالب، وحتى جهاز حاسوبك والشبكة. استخدام إضافة أمنيّة. استخدام CDN. استخدام شهادة SSL. تأمين كلمات السر الخاصة بك. لا تنسَ فحص نقاط الضعف في موقعك بانتظام للتأكد من أن موقعك خالٍ منها. ترجمة -وبتصرّف- للمقال Do You Know Why Hackers Are Targeting Your WordPress Site?‎ لصاحبه Brenda Barron
  13. في هذه السلسلة من الدروس، سنتحدث عن مكتبة jQuery Mobile ونتعرف عليها عن كثب والتي تساعدك على إنشاء مواقع ويب متجاوبة ومتوافقة مع الهواتف. تتضمن هذه السلسلة أكثر من 65 مثال تطبيقي عملي مع شيفراتها الكاملة. هذا الدرس جزء من سلسلة دروس تشرح jQuery Mobile: الدرس الأول: البداية، بناء وتقديم محتوى الدرس الثاني: التضمين، تهيئة الصفحة، التنقل بين الصفحات وأحداث التحميل الدرس الثالث: اتجاه الصفحة وأحداثها الدرس الرابع: ربط صفحات خارجية وتنظيم المحتوى بنظام الشبكة وبناء محتوى قابل للطي الدرس الخامس: الأيقونات والأزرار وإنشاء تنسيقات مخصصة الدرس السادس: إنشاء القوائم وتنسيقها وإنشاء نماذج البحث وتسجيل الدخول بدايتك مع jQuery Mobile ما هو jQuery Mobile المحمول يوفرjQuery Mobile مجموعة وفيرة من أدوات التطوير التي تجعل موقع ويب الموجه للهواتف متجاوبًا ومرنًا وبسيطًا. يُعرّف jQuery ببساطة على أنه مجموعة من إضافات وودجات (widgets) jQuery تهدف إلى توفير API متعدد المنصات لإنشاء تطبيقات ويب للهواتف. من حيث الشيفرات البرمجية، jQuery Mobile يشبه jQuery UI، لكن في حين أن jQuery UI موجه لتطبيقات سطح المكتب، فإن jQuery Mobile موجه للهواتف المحمولة. ما يجب معرفته حول إنشاء مواقع ويب للهواتف يجب عليك معرفة ثلاثة كلمات رئيسية عند تطوير مواقع ويب للهواتف، وهي أنه يجب أن يكون الموقع الموجه للهواتف: متجاوبًا: يتضمن كيف يبدو شكل الصفحة عند التنقل، وكيف يُضْغط على الزر وكيف تُحمّل البيانات على الهاتف. مرنًا: يعني أنه يمكن تخصيص الموقع عن طريق المستخدم ليناسب رغباته. بسيطًا: يعني أن الموقع يسهل تصفحه عن طريق الهاتف. ما يجب معرفته حول jQuery Mobile للمطورين أثّرت jQuery بشكل كبير على العالم الناشئ من تطوير وتصميم الويب، فلقد غيّرت من طريق تنفيذ واستخدام جافا سكربت على مواقع وتطبيقات الويب ولذلك اختارتها مايكروسوفت كإطار جافا سكربت المفضل، وضمّنت دعم الإكمال التلقائي (auto-completion) لـ jQuery داخل visual studio، وبالتالي فإن jQuery mobile هي امتداد مدعوم وموثوق لمكتبة jQuery. لماذا jQuery Mobile؟ (تحتاج إلى معرفة jQuery Mobile كمطور) كما أشرت في "ما يجب معرفته حول jQuery Mobile للمطورين”، أدى ظهور جيل أجهزة الهواتف إلى الحاجة إلى تطبيقات ويب متجاوبة ومرنة وبسيطة وبالتالي ارتفعت بسرعة الحاجة والطلب على jQuery mobile (إطار عمل jQuery)، وحان الآن الوقت بالنسبة لك كمعلم أو مبتدئ في API مواقع الهواتف الجوالة للقفز والمشاركة مع هذا المشروع. الجهاز الذي يُشغل jQuery Mobile يعتمد عمل jQuery في مختلف الأجهزة على المتصفح ونظام التشغيل. فالمتصفحات التي تدعم jQuery Mobile هي المتصفحات الحديثة التي تدعم وسوم HTML5 والقليل من CSS3. فالأجهزة التي تدعم jQuery mobile هي الحواسيب المكتبية والمحمولة، أنظمة الكل في واحد (all-in-one)، الأجهزة اللوحيّة، الهواتف الذكية، أندرويد، iOS، بلاك بيري (النسخ الحديثة)، webOS، ويندوز للهواتف، وأجهزة القراءة الإلكترونية، فيدعم jQuery mobile أجهزة كيندل kindle التي تتضمن متصفح مبني على Webkit تجريبي. ما يحتاجه المطور المحترف لإنشاء مواقع ويب للهواتف باستخدام jQuery Mobile لتطوير التطبيقات، ستستخدم: بالنسبة لنظام ويندوز التطبيقات: Komodo IDE، eclipse، iWeb، Microsoft FrontPage، Aptana studio، Dreamweaver، notepad++. وسنستخدم Dreamweaver في هذا الدرس. بالنسبة لنظام OsX التطبيقات: Coda، espresso، textwrangler، kod. لغات البرمجية التي يجب على مطور الويب معرفتها هي HTML5 و CSS3 وجافا سكربت. يتكون jQuery Mobile من أربعة ملفات: ملف جافا سكربت، ملف CSS، وملفي PNG. يُحمَّل ملف جافا سكربت بشكل مقصود بعد تحميل مكتبة jQuery الأساسية، ويقوم هذا الملف بمهام كثيرة مثل إنشاء الويدجات وتطبيق مستمعي الحدث (event listeners) وتفعيل API. ورقة أنماط CSS تحدد مخطط ومظهر عناصر صفحة jQuery Mobile، بالإضافة إلى تحديد الانتقالات (transitions) والرسوم المتحركة مع تحويلات CSS3. يمكنك تحميل كامل حزمة jQuery Mobile (مكتبة جافا سكربت، CSSـ والرسومات) أو يمكنك الوصول إليها عن طريق مشروع CDN، راجع صفحة تحميل مشروع jQuery Mobile للتفاصيل، سنستخدم CDN في أمثلتنا لهذا الدرس. DOCTYPE لبناء محتوى HTML لموقع الهاتف DOCTYPE انتقالي لـ HTML4 بالنسبة للمطورين الراضين باستخدام وسوم HTML المهملة لكن يريدون الانتقال إلى HTML 4 يمكنهم استخدام DOCTYPE الانتقالي والذي يسمح للمتصفح تحليل الوسوم المهملة وعرضها دون رمي (throw) أية أخطاء. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> DOCTYPE الصارم لـ HTML4 يمكن للمطورين الذي لا يرغبون بتضمين دعم للوسوم المهملة وإمكانية وجود أخطاء تنسيق عند استخدام وضع التوافق 'compatibility' استخدام DOCTYPE الصارم والذي يخبر المتصفح برمي أخطاء عند تضمين وسوم مهملة في ملف HTML عند محاولة تحميله، وسيكون هذا مفيدًا لضمان عملك على معيار HTML4. DOCTYPE من أجل HTML5 يعمل DOCTYPE للإصدار HTML5 تقريبًا على جميع المتصفحات القديمة وهو يُستخدم بالفعل على مواقع عديدة اليوم. لاستخدام HTML5 DOCTYPE في ملف HTML، استخدم المقتطف التالي: <!DOCTYPE html> هيكل الموقع الأساسي باستخدام HTML5 DOCTYPE <!DOCTYPE html> <html> <head><title></title></head> <body></body> </html> العمل مع هيكل HTML5 و CSS و جافا سكربت بناء وتقديم المحتوي في HTML5 <!DOCTYPE html> <html> <head> <title>Titles should be short descriptions of the page</title> <meta charset="utf-8"> </head> <body> <div> <h1>h1 tags should contain the most important information on your site</h1> <p>Paragraph tags should be where most of your text content lives, or used as a separation between sections.</p> <ul> <li>This is a list element</li> <li>This is another element, notice the bullets and indentation </li> </ul> <p>You probably noticed that I used a "div" tag to wrap these other tags in. I'm using it as a container.</p> </div> </body> </html> نعرف بالفعل ما تفعله هذه الشيفرة البرمجية، لكن دعنا نلقي نظرة حول شكله في الواقع. ستظهر لك الصورة في الأسفل شكل HTML الذي كتبناه: CSS في بناء وتقديم محتوى HTML5 اضغط على زر الإدخال بعد الوسم <title> </title> وأضف المقتطف كما هو موضح في رابط الصورة التالية لربط ملف الأنماط css. إلى ملف html. الرئيسي. يجب وضع الشيفرة البرمجية التالية في الملف hist.css @charset "utf-8"; /* CSS Document */ body { background:#0CF; font-family: Helvetica, Arial, sans-serif; font-size: 0.75em; } h1 { font-size: 200% } p { margin: 5px 0; padding: 0 3px; } #year{ text-align:center; font-weight:bold; font-size:200%; } .small { font-size: 80%; } تُظهر لك الصورة في الأسفل مظهر HTML الجديد بعد ربط ملف CSS . جافا سكربت في بناء وتقديم محتوى HTML5 ملخص لوضع وسوم جافا سكربت في ملفك: تحميل السكربتات في عنصر head: يجعلها تُحمّل أولا لكن قد تُؤثّر سلبا على وقت التحميل. تحميل السكربتات في body : تبدو فكرة جديدة لكنها تخلق مشاكل مع الصيانة وترمي (trows) تأخيرات التحميل المحتملة. تحميل السكربتات قبل إغلاق وسم body : سيبدو تحميل موقع أسرع لكن قد يؤدي ذلك إلى نتيجة غير مقصودة لنقص وظائف الموقع في الثواني الأولى للتحميل. دعنا نضع السكربتات في وسم head والتي هي الحالة المفضلة لكل مطور. <script src="js/javascript.js" type="text/javascript"></script> </head> يجب وضع السكربت التالي في ملف javascript.js // JavaScript Document window.onload = setYear; function setYear() { var currentYear = new Date(); document.getElementById('year').innerHTML = currentYear.getFullYear(); } ستوضح لك الصورة أدناه شكل HTML الجديد بعد ربط ملف js .. تعلمنا قليلا جول استخدام الحالي لهيكل HTML وربط CSS وتحميل السكربت (جافا سكربت)، والآن لنتعلم كيف نستخدم المهارات التي تعلمناها في jQuery mobile. ترجمة -وبتصرّف- للمقال jQuery Mobile Lesson 1 لصاحبه Andrew اقرأ أيضًا الدرس التالي: التضمين، تهيئة الصفحة، التنقل بين الصفحات وأحداث التحميل
  14. لقد استغرقت بعض الوقت لتعلم كيفية استخدام جافاسكربت في ووردبريس معنا، ولقد جمعنا أيضًا مجموعة من مكتبات جافاسكربت والمصادر على طول الطريق لمساعدتك في البرمجة، ولكن ما الذي ستفعله بالمهارات التي اكتسبتها؟ توجد العديد من الأسباب التي تجعلك تضيف جافاسكربت مخصص إلى موقع ووردبريس وتوجد أيضًا العديد من الطرق التي يمكنك من خلالها تنفيذ ذلك، لكن يجب أن تكون حذرًا حول كيفية القيام بذلك، فالتنفيذ الخاطئ لجافاسكربت يمكن أن يلحق ضررًا أكثر مما ينفع. في الدليل اليوم السريع لجافاسكربت، سنتحدث حول لماذا قد ترغب في إضافة شيفرات جافاسكربت مخصصة إلى موقعك وكيف تقوم بذلك بالطريقة الآمنة والسليمة (بما في ذلك استخدام إضافات ووردبريس). لماذا قد ترغب في إضافة جافاسكربت مخصص إلى ووردبريس عند كتابة الشيفرة البرمجية لموقع ووردبريس، توجد ثلاثة عناصر ستحتاجها: HTML CSS جافاسكربت إن HTML وCSS رائعين، فهما يضعان أساس موقع ووربريس الخاص بك، ومع ذلك، لا يمكنك استخدامهما لتغيير بعض سلوك موقعك، فعلى سبيل المثال، قد تحتاج إلى استخدام جافاسكربت للقيام بالتالي: تغيير، إخفاء، عرض عناصر HTML. إضافة قيم لمتغيرات CSS وتشغيل عمليات معقدة عليها مثل متغيرات الدمج أو توفير رد بعد اتخاذ إجراء (مثل نقرة). تغيير تخطيط وتصميم قوالب ووردبريس الخاص بك (إذا كنت محظور من التحكم على بعض العناصر). تغيير أو تعزيز وظيفة إضافة ووردبريس. عزز موقعك مع محتوى حيوي مثل مربعات التمرير (sliders)، والرسوم المتحركة (animation)، ومشغلات الفيديو، والقوائم المنسدلة، وتأثيرات التمرير، والآلة الحاسبة، والعناصر التفاعليّة الأخرى. ربط مصدر خارجي أو عنصر إلى موقعك، مثل Google Analytics أو API من مصادر خارجية. وهنا يمكن لجافاسكربت مساعدتك. ومع ذلك، إن تطبيق شيفرات جافاسكربت ليس سهلًا مثل HTML و CSS، ليس عليك فقط أن تكون حذرًا حول كيفية كتابة التعليمات البرمجية ولكن عليك أيضًا أن تكون حذرًا حول كيف وأين يمكنك إضافتها إلى ووردبريس. كيفية إضافة جافاسكربت مخصصة إلى ووردبريس إذا أتقنت HTML وCSS و تريد إضافة بعض الحيوية إلى موقعك سيكون الوقت مناسبًا لإضافة شيفرات جافاسكربت مخصصة إليه، لكن كيف يمكنك القيام بذلك وأين يمكنك وضعه؟ والأهم من ذلك، هل هذا الأمر مهم؟ كقاعدة أساسيّة، ينتمي جافاسكربت إلى أحد هذه الأماكن: في رأس القالب لسكربتات تطبيقات جانب الموقع. داخل جسم صفحة ويب للتطبيقات الصفحة الخاصة. لا يجب عليك إضافة كامل الشيفرة البرمجية في تلك الأماكن، إذا أردت تسريع تحميل صفحات الويب وتسهيل قراءة الشيفرة البرمجية، يمكنك إنشاء ملفات جافاسكربت مستقلة (‎.js) واستدعائها باستخدام مرجع مثل هذا: filename.js تبدو بسيطة، أليس كذلك؟ حسنًا، تذكر أن جافاسكربت هي لغة برمجة، وليس شيء يمكنك حقنه بسهولة في صفحات الويب مثل HTML وCSS، لذا، هذه بعض القواعد التي يجب عليك اتباعها عند إضافة جافاسكربت مخصصة إلى موقع ووردبريس: القاعدة رقم1: لا تستخدم محرر ووردبريس ما لم تضف سكربت صغير للغاية إلى صفحة منفردة أو تستدعي ملف منه، فمحرر ووردبريس للصفحات ليس مكانًا مناسبًا لكتابة شيفرات جافاسكربت، وسيبطئ من تحميل صفحتك وستخلق فوضى في الشيفرات البرمجية. القاعدة رقم2: لا تعدّل ملفاتك مباشرةً تتعلّق هذه القاعدة بملفات القوالب والإضافات، فعلى الرغم من أن جافاسكربت سيساعدك على إضافة أو تغيير وظيفة في ووردبريس، إلا أنه من السيئ إضافة شيفرة جافاسكربت مخصصة إلى ملفات الرأس هذه (header files). من أهم الأخطاء التي يرتكبها المبتدئين هي إفساد الشيفرات البرمجية المكتوبة جيّدًا من قبل المطور، وواحدة من الطرق التي تحافظ على عمل موقعك بشكل طبيعي هي تطبيق الممارسات الصحيحة أثناء البرمجة، لأن شيفرة جافاسكربت خاطئة قد تفسد ذلك. ثانيًا، ستخسر توجيهات جافاسكربت المخصصة عند تحديث القالب أو الإضافة، فعلى الرغم من أن جافاسكربت ينتمي إلى رأس القالب ويمكنك تعديل ملف header.php، لكن لا تفعل هذا. وأخيرًا، إذا كنت تفكر في التحايل على هذه المشكلة من خلال إنشاء "قالب فرعي" وتطبيق جافاسكربت المخصصة هناك، فلا تقم بذلك، فعند تحديث ملفات header.php أو footer.php باستخدام جافاسكربت، فقد تنشئ عن غير قصد تعارضًا مع إضافات أخرى تعمل في موقعك، وهذا سيبطئ من سرعة موقعك أو سيتوقف موقعك بالكامل لأنه لا يعرف كيفية التعامل مع هذه الطلبات المتزامنة. ملاحظة: تتعلق هذه القاعدة بالمطورين الذين يستخدمون إضافات أو قوالب من مصدر ثالث، فإذا كنت تكتب قوالبك أو إضافاتك بنفسك، فيمكنك إضافة جافاسكربت مباشرةً إلى ملف header، ومع ذلك، ستحتاج إلى استخدام نظام صفْ كما يشرحه المقال التالي. القاعدة رقم3: إنشاء ملفات منفصلة لجافاسكربت نصحناك بعدم إضافات شيفرات جافاسكربت مباشرة إلى الملفات أو الصفحات في ووردبريس، فما هي الطريقة الصحيحة لإضافتها؟ هنالك طريقتين لفعل ذلك، الأولى عن طريق إنشاء ملفات جافاسكربت منفصلة والثانية والتي سأشرحها في القاعدة رقم 4، هي عن طريق استخدام إضافات ووردبريس. كما ذكرنا سابقًا، ستسبب إضافة شيفرات جافاسكربت مخصصة مباشرةً إلى ووردبريس فوضى في الشيفرات البرمجية وقد تؤدي إلى مشاكل خطيرة مثل شاشة الموت البيضاء، لكن إذا أردت فقط تطبيق سكربت إلى صفحة واحدة، فستحتاج إلى طريقة لحقن الشيفرة البرمجية في المكان المخصص بدلا من إضافتها والضغط على بقية الصفحات الأخرى بطلبات HTTPS غير ضروريّة. لذا يجب عليك إنشاء ملف جافاسكربت منفصل. يتضمن ووردبريس Codex على بعض الخطوات حوّل ما يجب عليك فعله مع ملفك، ولتسهيل الأمر، ينصح بالتالي: مهما كان عدد السكربتات، تأكد من تعريف الدالة لكل سكربت داخل الملف، فعلى سبيل المثال: بعد ذلك، استدعي الملف من رأس موقعك عن طريق استخدام سكربت مثل هذا (يمكنك إضافة هذا إلى الرأس باستخدام إضافة): وأخيرًا، ستحتاج إلى استدعاء دالة جافاسكربت الحاليّة التي عرّفتها في الملف حتى لو كان هنالك سكربت واحد فقط فستحتاج إلى تعريفه في شيفرتك البرمجية. إذا كانت شيفرة جافاسكربت تنطبق على كامل الصفحة أو الموقع، يمكنك إضافة استدعاء جافاسكربت التالي إلى الرأس (header)، وإذا احتجت إلى تنفيذ جافاسكربت في مكان ما في الصفحة، فيجب أن يكون داخل جسم موقعك: القاعدة رقم 4: استخدام إضافة ووردبريس عندما يتعلق الأمر بجافاسكربت، ستساعدك الإضافات التالية على الالتفاف على المشكلات التي تنشأ عند وضع جافاسكربت مباشرةً في ملفات ووردبريس، فبدلًا من ذلك، ستسمح هذه الإضافات للخادم باستدعاء السكربت فقط عند حدوث "الحدث”، ويسمح لك هذا بالالتفاف على ثيمات وإضافات ووردبريس عند التحديث والذي يمسح لك أيّة تغييرات طبّقتها مباشرةً عليهم. إضافة Insert Headers and Footers أُنشأت هذه الإضافة بواسطة WP Beginner لمساعدة المطورين على إضافة شيفرات برمجية مخصّصة بسهولة إلى رأس وذيل القوالب، فهو يعطيك أداة مريحة - خارج ملف header.php – التي تسمح لك بإضافة جميع السكربتات المخصّصة، فقط كن على علم بأن هذا البرنامج هو المساعد مثالي لك فقط إذا كنت تحاول إجراء تغييرات على جانب الموقع باستخدام جافاسكربت. على الرغم من وجود إضافتين لإضافة الشيفرات إلى الرأس والذيل في مستودع ووردبريس، إلا أن هذه من WP Beginner هي الأكثر شعبيّة. إضافة Shortcoder بالنسبة إلى الأشخاص الذين يرغبون بإضافة شيفرات جافاسكربت مخصصة إلى صفحات أو مشاركات فرديّة، فقد ذكرْتُ عدة طرق يمكنك من خلالها إجراء ذلك أعلاه، فيمكنك إما إضافته إلى HTML مباشرةً إذا كان السكربت صغيرًا أو يمكنك استدعاء ملف جافاسكربت الذي يمكنه حمل كامل شيفرتك البرمجية، كِلا هاتيّن الطريقتين تضيفان عددًا من الأسطر البرمجية إلى موقعك ويمكن أن يجعل الأمور أكثر تعقيدًا وأكثر صعوبة عند القراءة، لذا يمكنك حل ذلك عن طريق استخدام إضافة Shortcoder. من الفوائد الأخرى لاستخدام Shortcoder هي اختصار الوقت، لنفترض أن لديك دالة جافاسكربت خاصة تريد تطبيقها على صفحاتٍ كثيرةٍ، فلن تحتاج إلى نسخ السكربت إلى كل واحدة منهم، فيمكنك إنشاء شيفرة برمجية مختصرة لتمثيل تلك الدالة وإضافتها في أي مكان تحتاج إليه. خاتمة إن فهم كيفية استخدام جافاسكربت لتعزيز قوة قوالب، وإضافات، ومحتوى ووردبريس هي طريقة قويّة لتعزيز قدرتك على تطوير ووردبريس، ومع ذلك، يجب أن تكون حذِرا في كيفية استخدامها حتى لا تعطّل أداء موقعك أو تتسبب في مشكلات تكامل التي تحاول تشغيلها في موقعك، التزم بالقواعد أعلاه وستكون على ما يرام. ترجمة -وبتصرّف- للمقال Learn How to Add Custom JavaScript to WordPress the Right Way لصاحبه Brenda Barron
  15. يجب أن يهتم كل شخص يمتلك، أو يبني، أو يدير أو يستضيف مواقع ووردبريس بالأمن، ليس لأن ووردبريس منصة غير آمنة بل لأنه نظام إدارة المحتوى الأشهر في العالم وهو هدف سهل للمخترقين ولذلك لا يجب على مدونات ووردبريس التوقف عن الحديث حول أمن ووردبريس. من فوائد الاهتمام الكبير بالأمن وجود مجموعة كبيرة من الحلول لمعالجة ذلك، فعلى سبيل المثال، توجد أدوات مراقبة أمنية مثل WP Checkup ستهتم بالجزء الأول من المعركة ضد نقاط ضعف ووردبريس، ولكن هذا ليس كافيًا، ستحتاج أيضًا إلى أدوات تمكنك من إصلاح الثغرات الأمنية والانتهاكات. هذا هو سبب وجود إضافات ووردبريس أمنيّة، وبالتأكيد، يجب عليك استخدام أدوات أخرى وجدران حماية خارج ووردبريس، لكن هذه الإضافات تساعدك على وضع جدار دفاعي قوي داخل موقعك، وإذا لم تكن معتادًا على إضافة Defender، فأنصحك بإلقاء نظرة عليها. يوجد الكثير من الأشياء داخل هذه الإضافة – في كلا الإصدارين المجاني والمدفوع- لذلك لنكتشفهم ونرى كيف يمكنك الاستفادة القصوى من هذه الإضافة. دافع عن موقع ووردبريس الخاص بك باستخدام النسخة المجانية من إضافة Defender بالنسبة إلى الأشخاص الخائفين من الانتقال مباشرة إلى إضافة ووردبريس مدفوعة (خاصة لواحدة تتعامل مع أمن ووردبرس) دون تجربتها، هنالك أخبار جديدة، يمكنك تحميل Defender مجانا من مستودعات ووردبرس. لنلق نظرة فاحصة على المميزات التي تحتاجها للاستفادة من النسخة المجانية من Defender والحصول على أقصى استفادة لزيادة الأمن الخاص بك: تحصين تسجيل دخول ووردبريس على الرغم من أن لوحة تحكم Defender تركز على أشياء مثل ترتيب قاعدة البيانات وإضافة تدابير أمنية جديد إلى أشياء مثل PHP ومحرر الملفات، إلا أنني أقترح عليك بالبدء في قسم IP Lockouts من الإضافة. صحيح أن Defender يعطي أولوية لفحص (Scanning) وتنظيف (cleanup) ووردبريس من داخل لوحة التحكم، لكن، على الرغم من ذلك، تأكد من إغلاق بابك الأمامي أولًا (على سبيل المثال صفحة تسجيل الدخول). عندما تحصّن تسجيل الدخول ضد هجمات القوة العمياء (brute force) عن طريق التأكد من عناوين IP والقوائم السوداء، فستتمكن من استخدام هذه الإضافة لتنشيط المراقبة (monitor) وإصلاح موقعك. ابدأ بـ Advanced Tools، فسيتيح لك هذا القسم تشغيل المصادقة الثنائية (two-factor authentication) لمستخدمي ووردبريس. بالإضافة إلى ذلك، توجد إعدادات إضافية يجب تكوينها، مع هذه الخيارات، يمكنك تسهيل الحصول على أداة مصادقة جوجل (Google Authenticator) للمستخدمين، ويمكنك أيضًا استخدامها لمراقبة المستخدمين والتأكد من التزامهم بأفضل الممارسات لتأمين كلمة المرور. الآن، لننتقل إلى قسم IP Lockouts، ويمكنك استخدام هذه الأساليب لتحصين عملية تسجيل الدخول: قواعد تسجيل الدخول، والقيود، وعمليات الإغلاق (Lockouts). حظر برامج التتبع عن طريق خطأ 404. حظر IP ووضعه في القائمة السوداء (أو وضعه في القائمة البيضاء). لا تنسَ أيضًا استخدام إعدادات Logs و Notifications لإعلامك بانتظام عند حدوث محاولات دخول خبيثة إلى نظام تسجيل الدخول. اتبع إجراءات الأمان الموصى بها من الأفضل لو ألقى شخصا ما نظرة على موقعك وأخبرك ماذا تفعل؟ هذا ما يفعله Defender عن طريق Security Tweaks، وليس هذا فقط بل يقدم لك تفسيرات كاملة لكيفية تأمين موقعك بنجاح: سيخبرك Defender أيضًا أين توجد المسائل الخطرة وكيفية إصلاحها: وهذا سيسهّل عليك تحديد نقاط ضعف موقعك وكيفية إصلاحها، ما عليك سوى الضغط على زر “Fix the Issue” عندما تكون مستعدًا أو “Ignore” لتخطيه والانتقال إلى الخطوة التالية. افحص ملفاتك هل قلقت على ما سيفعله المخترقون بملفاتك خلف الكواليس؟ على سبيل المثال، صفحة الموت البيضاء أو بعض الثغرات الواضحة في واجهة موقع ووردبريس قد تُكسِب شخصًا ما وصولًا غير مبرر، لكن كيف يفترض بك أن تعرف حدوث ذلك في قاعدة بياناتك؟ فهي ليست كتمشيط ملفاتك أو البرمجة بالأسلوب المعتاد، فكيف يمكنك اكتشاف شيء مثل هذا؟ ستهتم إضافة Defender بهذا لك على المستوى الأساسي. عندما تستخدم أداة File Scanning، سيفحص Defender الملفات الأساسية وللكشف عن أي تغيير لم يتوقع العثور عليه، فإذا اكتشف أي من هذا، فسينذرك Defender بذلك، وللحصول على هذه التنبيهات، تأكد من تحديث الإعدادات في File Scanning لكي تظهر للشخص المناسب وحتى تعرف ما الذي تبحث عنه بالضبط (إذا اخترت تخصيص الرسالة). وبمجرد رؤيتك لنتائج الفحص، لديك خياران، إما إصلاحها واستعادة الملف مرة أخرى بضغطة زر واحدة، أو إذا كنت تعرف الملف وترغب في الاحتفاظ به كما هو، فتجاهل هذا التحذير ببساطة. دافع عن موقع ووردبريس الخاص بك عن طريق إضافة Defender المدفوعة إذا كنت تملك عضوية في WPMU DEV أو كنت تنوي ترقية الإضافة Defender إلى الإصدار المدفوع، فهذا القسم لك. تتشابه النسخة المدفوعة مع النسخة المجانية عند تشغيلها لأول مرة في ووردبريس، لذلك لا تنزعج، فعلى الرغم من امتلاكها لنفس لوحة التحكم، إلا أنها تمتلك مجموعة كبيرة من مميزات الأمنية الإضافية لموقعك. وهذه التي تحتاج إلى الاستفادة منها الآن: التحقق من حالة القائمة السوداء لا أحد يريد أن يكون في القائمة السوداء، وخاصة عندما يتعلق الأمر بموقع ووردبريس. وإذا لم تعرف هذا، فهذا يعني أن محركات البحث حظرت موقعك لأنه يشكل تهديدًا أمنيًا للمستخدمين، ومع ذلك، فليس كما لو كانت جوجل سترسل إليك رسالة إلكترونية تقول فيها "أهلا، قررنا حظر موقعك من البحث”، لكن بدلًا من ذلك، ستحتاج إلى أداة مثل هذه لتخبرك عندما يحدث ذلك. بمجرد أن يكتشف Defender أن موقعك أُدرج في القائمة السوداء، يمكنك بدء البحث في جميع عمليات الفحص والسجلات لتحاول معرفة مصدر الخرق وإغلاقه في أسرع وقتٍ ممكن. عمليات فحص تلقائية في النسخة المجانية من هذه الإضافة، ستجد خدمة فحص ومراقبة أمنيّة مدمجة في Defender، ومع ذلك، ماذا لو كان بإمكانك جعلها أسهل لفحص موقعك وإعلامك بالنتائج؟ وماذا لو رغبت في فحص المشاكل في أجزاء غير الجوهر؟ حسنًا، هذا هو سبب ترقيتك إلى النسخة المدفوعة. باستخدام الإضافة المدفوعة، يمكنك فحص: جوهر ووردبريس. إضافات قوالب ووردبريس. شيفرات برمجية مشبوهة موجودة في موقعك. ويمكنك أتمتة الفحص أيضًا حتى تتمكن من الاطمئنان أن شخص آخر يراقب أمن موقعك حسب حاجتك. تلقي سجلات التدقيق بالإضافة إلى مراقبة الجوهر والبرامج المثبتة في ووردبريس، يمكنك أيضًا تشغيل سجلات التدقيق (audit logs) داخل Defender. سيراقب Defender بشكل افتراضي جميع الخطوات التي تقوم بها على موقعك، اعتبره نظام مراقبة خاص يخبرك من قام بالفعل، لأي ملف وفي أي وقت. وهذا الأمر مفيد عند تعقب تصرفات المخترقين في موقعك، بالإضافة إلى أنه مفيد عندما "يكسر” موظف أو عميل شيئًا وتحتاج إلى معرفة ما الذي حدث. تسمح لك Event Logs بإجراء عمليات بحث أكثر تفصيلًا في السجلات لتحديد الأماكن التي انحرفت فيها الأمور، مما يوفر لك الوقت لتحري الخلل وإصلاحه عندما تشعر بالعجز عن رؤية سبب المشكلة. إنشاء تقارير أمنية مخصصة وتلقائيّة هذه طريقة أخرى تجعل فيها النسخة المدفوعة أمن موقعك أسهل بالنسبة لك. بالتحديد، توجد ثلاثة تقارير أمنية يمكنك إنشاؤها، تخصيصها وجدولتها في Defender: فحص الملفات. سجلات التدقيق. إغلاق IP. ذكرنا كل واحد منها في هذا المقال، لكن ما لم نذكره كان كم من السهل تخصيصه وأتمتة إرسال هذه التقارير الأمنية إليك (ولبقية المسؤولين) عن استخدام النسخة المدفوعة. عملية الإعداد سهلة للغاية: ببساطة، اختر التكرار والوقت التي ترغب فيه في الحصول على التقرير ومن ثم ستعرف ما الذي يحدث من الإغلاق إلى نشاط مدقق دون الحاجة إلى تسجيل الدخول مرة أخرى إلى ووردبريس. خاتمة ليس الهدف من إضافات ووردبريس تركيبها وتركها، فإذا أردت حقًا الاستفادة من جميع مميزات Defender (ناهيك على إضافات ووردبريس الأخرى) ستحتاج إلى معرفة كيف تعمل، وبهذه الطريقة، يمكنك ضبطها لتحسين سير العمل وزيادة النتائج. ترجمة -وبتصرّف- للمقال Get the Most Out of Defender and Maximize WordPress Security لصاحبته Brenda Barron.