اذهب إلى المحتوى

البحث في الموقع

المحتوى عن 'navigation'.

  • ابحث بالكلمات المفتاحية

    أضف وسومًا وافصل بينها بفواصل ","
  • ابحث باسم الكاتب

نوع المحتوى


التصنيفات

  • الإدارة والقيادة
  • التخطيط وسير العمل
  • التمويل
  • فريق العمل
  • دراسة حالات
  • التعامل مع العملاء
  • التعهيد الخارجي
  • السلوك التنظيمي في المؤسسات
  • عالم الأعمال
  • التجارة والتجارة الإلكترونية
  • نصائح وإرشادات
  • مقالات ريادة أعمال عامة

التصنيفات

  • مقالات برمجة عامة
  • مقالات برمجة متقدمة
  • PHP
    • Laravel
    • ووردبريس
  • جافاسكربت
    • لغة TypeScript
    • Node.js
    • React
    • Vue.js
    • Angular
    • jQuery
    • Cordova
  • HTML
  • CSS
    • Sass
    • إطار عمل Bootstrap
  • SQL
  • لغة C#‎
    • ‎.NET
    • منصة Xamarin
  • لغة C++‎
  • لغة C
  • بايثون
    • Flask
    • Django
  • لغة روبي
    • إطار العمل Ruby on Rails
  • لغة Go
  • لغة جافا
  • لغة Kotlin
  • لغة Rust
  • برمجة أندرويد
  • لغة R
  • الذكاء الاصطناعي
  • صناعة الألعاب
  • سير العمل
    • Git
  • الأنظمة والأنظمة المدمجة

التصنيفات

  • تصميم تجربة المستخدم UX
  • تصميم واجهة المستخدم UI
  • الرسوميات
    • إنكسكيب
    • أدوبي إليستريتور
  • التصميم الجرافيكي
    • أدوبي فوتوشوب
    • أدوبي إن ديزاين
    • جيمب GIMP
    • كريتا Krita
  • التصميم ثلاثي الأبعاد
    • 3Ds Max
    • Blender
  • نصائح وإرشادات
  • مقالات تصميم عامة

التصنيفات

  • مقالات DevOps عامة
  • خوادم
    • الويب HTTP
    • البريد الإلكتروني
    • قواعد البيانات
    • DNS
    • Samba
  • الحوسبة السحابية
    • Docker
  • إدارة الإعدادات والنشر
    • Chef
    • Puppet
    • Ansible
  • لينكس
    • ريدهات (Red Hat)
  • خواديم ويندوز
  • FreeBSD
  • حماية
    • الجدران النارية
    • VPN
    • SSH
  • شبكات
    • سيسكو (Cisco)

التصنيفات

  • التسويق بالأداء
    • أدوات تحليل الزوار
  • تهيئة محركات البحث SEO
  • الشبكات الاجتماعية
  • التسويق بالبريد الالكتروني
  • التسويق الضمني
  • استسراع النمو
  • المبيعات
  • تجارب ونصائح
  • مبادئ علم التسويق

التصنيفات

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

التصنيفات

  • الإنتاجية وسير العمل
    • مايكروسوفت أوفيس
    • ليبر أوفيس
    • جوجل درايف
    • شيربوينت
    • Evernote
    • Trello
  • تطبيقات الويب
    • ووردبريس
    • ماجنتو
    • بريستاشوب
    • أوبن كارت
    • دروبال
  • الترجمة بمساعدة الحاسوب
    • omegaT
    • memoQ
    • Trados
    • Memsource
  • برامج تخطيط موارد المؤسسات ERP
    • تطبيقات أودو odoo
  • أنظمة تشغيل الحواسيب والهواتف
    • ويندوز
    • لينكس
  • مقالات عامة

التصنيفات

  • آخر التحديثات

أسئلة وأجوبة

  • الأقسام
    • أسئلة البرمجة
    • أسئلة ريادة الأعمال
    • أسئلة العمل الحر
    • أسئلة التسويق والمبيعات
    • أسئلة التصميم
    • أسئلة DevOps
    • أسئلة البرامج والتطبيقات

التصنيفات

  • كتب ريادة الأعمال
  • كتب العمل الحر
  • كتب تسويق ومبيعات
  • كتب برمجة
  • كتب تصميم
  • كتب DevOps

ابحث في

ابحث عن


تاريخ الإنشاء

  • بداية

    نهاية


آخر تحديث

  • بداية

    نهاية


رشح النتائج حسب

تاريخ الانضمام

  • بداية

    نهاية


المجموعة


النبذة الشخصية

تم العثور على 5 نتائج

  1. ناقشنا في الدروس الماضية كيف نفهم ونُخطّط لتصميم تجربة المُستخدم، سنبدأ اليوم بالعمل الحقيقيّ. أوّل خطوة في تصميم حلّ متكامل هي تأسيس البُنية العامّة، وهذا يعني أنّ علينا التّعرف على معنى هندسة المعلومات (Information Architecture). فهرس سلسلة مدخل إلى تجربة المستخدم: مدخل إلى تجربة المستخدم User Experience فهم ودراسة المستخدمين في مجال تجربة المستخدم دراسة الشريحة المستهدفة في مجال تجربة المستخدم كيفية التصميم للأجهزة المختلفة هندسة المعلومات في تجربة المستخدم (هذا الدرس) تعرف على أنماط التصميم في مجال تجربة المستخدم أشياء لا يمكن اعتبارها رسوما تخطيطية (Wireframes) في مجال تجربة المستخدم تعرف على الرسوم التخطيطية (Wireframes) في مجال تجربة المستخدم مفهوم الثقل المرئي (Visual Weight) والألوان في مجال تجربة المستخدم التكرار ومخالفة الأنماط في مجال تجربة المستخدم المحاذاة والقرب في مجال تجربة المستخدم تعرف على أساليب مسح الواجهة والتراتب المرئي في مجال تجربة المستخدم أساليب الإطلاع في مجال تجربة المستخدم: التصفح، البحث والاكتشاف تصميم هيكل صفحة الويب والعناصر الأساسية في مجال تجربة المستخدم الأزرار، النماذج والدعوات إلى الإجراء في مجال تجربة المستخدم استخدام علم النفس في مجال تجربة المستخدم لتكييف المستخدم وإقناعه كيف تغير الخبرة من تجربة المستخدم؟ تصميم تجربة المستخدم من خلال بيانات وإحصائيات المستخدمين تعرف على أنواع المخططات الإحصائية في مجال تجربة المستخدم اختبارات أ/ب (A/B Test) في مجال تجربة المستخدم تكون هندسة المعلومات (أو IA اختصارًا) بسيطة نسبيًّا في المشاريع الصّغيرة، ولكنّها تصبح غايةً في التّعقيد في مشروع ضخم. بنية المعلومات هي مفهوم غير ملموس، ولكي نتعامل معه، علينا أوًّلا رسم خريطة للموقع، كهذه مثلًا: يعرض هذا المثال موقعًا فيه 6 صفحات: الرئيسيّة، وقسمان في القائمة الرئيسيّة، و 3 أقسام فرعيّة. تمثّل الخطوط الصّفحات المرتبطة من خلال عناصر التّنقّل (navigation) وهي القوائم والأزرار. ملاحظة: عندما تُرتّب الصّفحات بهذا الأسلوب (كشجرة عائلة)، نُسمّيها "شجرة" أو "سلسلة هرميّة" (hierarchy)؛ وهي مُستخدمة في تنظيم معظم التّطبيقات والمواقع (إلّا أنّها ليست الأسلوب الوحيد). ما من قواعد صارمة في رسم خريطة الموقع، ولكن إليك بعض الإرشادات العامّة: الخريطة البسيطة لا تعني بالضّرورة ترتيبًا منطقيًّا للمعلومات. أبقِ الخريطة سهلة القراءة وواضحة. عادةً نرسم من الأعلى للأسفل، وليس من اليسار لليمين [أو العكس]. ليس بالضّرورة أن تكون الخريطة جميلة المظهر، فهي مُستند تقنيّ وليست عرض أزياء! الخريطة إما أن تكون عميقة أو مسطحة بشكل عام، عليك أن تجعل الخريطة مُسطّحة قدر الإمكان (وهذا يعني إضافة الأقسام الفرعيّة في القائمة وبالتّالي لا يضطر المستخدم إلى النّقر مرّات كثير للوصول إلى عمق الموقع)، أو أن تجعلها عميقة (وهذا يعني قوائم أبسط لكنّها تحتاج نقرات أكثر). لاحظ أن للبنيتين أعلاه العدد نفسه من الصّفحات، ولكنّهما مختلفتان. بعض المواقع الّتي تقدّم منتجات كثيرة مثل Wal-Mart تحتاج عادةً بنية عميقة وإلّا أصبحت القائمة ضخمةً، بينما تحتاج مواقع أخرى مثل YouTube بنية مُسطّحة لأنّها لا تتضمّن غير مفهومين: المُستخدمين ومقاطع الفيديو. أسوأ الأمور أن تجعل موقعك عميقًا و مُسطّحًا في الوقت ذاته، عليك حينئذٍ تبسيط أهدافك، أو تصميم مربّع بحث وعرضه كمكوّن أساسيّ. خرافة شائعة: قد تسمع البعض يقول أن كلّ شيء في الموقع ينبغي أن يكون على بُعد 3 نقرات دومًا. هذا يعني أنّك تعلّمت تجربة المُستخدم في التّسعينيّات ولم تتعلّم شيئًا بعد ذلك. ركّز على المُستخدم، تأكّد من أنّهم يعرفون مكانهم في الموقع، وكيف يمكن أن يتنقّلوا، لا يهمّ عدد النّقرات إن كان التّنقّل واضحًا ويسيرًا. قصص المستخدمين (User Stories) تصف "قصّة المُستخدم" إحدى الطّرق الّتي يمكن أن يسلكها المُستخدم ضمن موقعك أو تطبيقك، ويجب أن تكون القصّة موجزة وكاملة معًا، وستحتاج إلى أكثر من قصّة لشرح تصميمك بالكامل. فيما يلي مثّال عن قصّة مستخدم يزور موقع Google: يصل المستخدم إلى صفحة البحث الرئيسيّة. يُدخِل المستخدم عبارة بحث ويُرسلها بالنّقر أو بلوحة المفاتيح. تعرض الصّفحة التّالية قائمة بنتائج البحث تكون مرتبّة بحسب مُلائمتها لعبارة البحث. يمكن للمُستخدم النّقر على الرّابط للوصول إلى الموقع المُناسب، أو تصفّح المزيد من نتائج البحث حتّى يجد شيئًا يُفيده. ملاحظة: هذا المثال مُبسَّط، ولكنّ كافٍ لشرح الفكرة. لاحظ أنّه ما من شيءٍ في القصّة يشرح تفاصيل التّصميم، وإنّما فقط يفرض إمكانيّتها، فغرض قصّة المُستخدم شرح مسير الاستخدام، أي تتابع خيارات المُستخدم، وليس الواجهة النّهائيّة للمشروع. إن كان مسير المُستخدم بسيطًا وفعّالًا، فقد أحسنت صنعًا (حتى الآن!) يميل مُدراء المشاريع إلى الاعتقاد أنّ قصّة المستخدم هي ذاتها تجربة المُستخدم، وهذا خاطئ، لأنّها ببساطة تُمثّل قائمة من المزايا والوظائف، فمصمّم تجربة المُستخدم يضع هذه القصص الّتي بدورها تُحوّل إلى الفريق. الآن وقد أصبح بإمكاننا كتابة قصص المستخدم، علينا أن نبني هندسة المعلومات، فبنية الصّفحات تُحدّد الخطوات الّتي تقوم عليها قصّة المستخدم، وعلينا أن نختار نوع هندسة المعلومات الّتي نرغب بتنفيذها، وربّما نحتاج عدّة أنواع. أنواع هندسة المعلومات الفئات (Categories) المهمّات (Tasks) البحث الزّمن النّاس الفئات لنفكّر مثلًا في متاجر بيع الملابس بالتّجزئة: يمكن تخيّل قائمة من مجموعة فئات: "الرّجال، والنّساء، والأطفال، والتّخفيضات" وهكذا... تُشير هذه الفئات إلى أنواع المحتوى المتوفّر، عندما تنقر على إحداها، ستتوقّع محتوىً ينتمى إلى الفئة المعنيّة. هذا أكثر أنواع هندسة المعلومات شيوعًا، ولكن قد تكون الفئات أكثر تعقيدًا، وعندها قد تعتري الحيرة مُستخدميك عندما يزورون فئة لا تحتوي ما يطلبونه. المهمات من الطرق الأخرى تنظيم المعلومات في الموقع أو التّطبيق توزيعها بحسب الأهداف الّتي يريد المُستخدمون إنجازها، فإن كنت تصمّم موقعًا لمصرف، قد يكون من المناسب تصميم قائمة تحتوي "التوفير، القروض، الاستثمارات، المساعدة، فتح حساب". إن كان مُستخدمك يعرف بالضّبط ما يُريد، فهذه من أفضل الطّرق لهندسة المعلومات، ولكن توخّ الحذر: فقد لا يعلم كلّ المُستخدمين ما يُريدون. فكّر قليلًا في النّوعين السّابقين، تصميم قائمة لموقع واحدٍ بأحد هذين النّوعين يختلف كثيرًا عنها بالنّوع الآخر، واعتماد أحدهما يتطلّب اهتمامك. البحث إن كان موقعك شديد التّعقيد، أو مليئًا بمحتوى يُنتجه المُستخدمين، فقد يكون من الأفضل اللجوء إلى البحث، مثل YouTube، فلو لم يحوِ YouTube إلا فئات المقاطع (مضحكة، أفلام، إعلانات...) لكان صعب الاستخدام، كما أنّ ذلك يعني الحاجة دومًا إلى تصنيف الفيديوهات المنشورة بشكل صحيح. الزمن إن كنت مُبتدئًا في تجربة المُستخدم فقد تُربكك هذه الفكرة: يمكنك تصميم هندسة معلومات تتغيّر مع الزّمن، فمثلًا: صندوق البريد الإلكتروني، حيث تعرض الرّسائل بترتيب وصولها، هذا تصميم قائم على الزّمن، في مواقع المحتوى قد تستخدم فئات مثل "شائع، مؤرشف، حديث..."، نشرة الأخبار في فيسبوك مثال على هذا. الناس فيسبوك أيضًا مثال على هندسة معلومات قائمة على النّاس، فكلّ الصّفحة مصمّمة حول فكرة لمن تعود هذه المعلومات، والعلاقات بين النّاس، عندما تصل إلى صفحة شخص ما، تتحوّل هندسة المعلومات إلى نوع الفئات (صور، أصدقاء، أماكن) لتصنيف هذه الأنواع المختلفة من المحتويات. قد يكون هناك أنواع عديدة أخرى! لكنّ مقالتنا أصبحت طويلة بعض الشيء. ترجمة بتصرّف للدرسين What is Information Architecture و User Stories & Types Of Information Architecture من سلسلة Daily UX Crash Course لصاحبها Joel Marsh. اقرأ أيضًا النسخة العربية الكاملة من كتاب مدخل إلى تجربة المستخدم (User Experience - UX) 1.0.0 التصميم للهواتف: هندسة المعلومات كيف تعيد تصميم موقع إلكتروني قائم بالشكل الصحيح كيف تنشئ منزلِقا Slider مناسبا للواجهة الرسومية عند التصميم للجوال
  2. في هذا الدرس سوف تتعلم كيفية إنشاء قائمة تنقل (navigation) دائرية الشكل باستخدام CSS Transforms. سوف أريك كيف تقوم بذلك خطوة بخطوة وسوف أقوم بشرح الحسابات والمنطق البسيط وراء هذه الطريقة حتى يتسنى لك فهم كيفية عمل هذه الطريقة. وكما ذكرت قبل قليل فسوف يكون هناك بعض الحسابات، ولكن لا تقلق فلن يكون هناك أي شيء معقد أو يصعب فهمه وسوف أشرح كل شيء خطوة بخطوة. بنية HTML بما أننا سنقوم ببناء قائمة تنقل فسوف نبدأ بالبنية المعتادة لأي قائمة، أي أننا سوف نحتاج إلى عنصر div ليحتوي على قائمة العناصر المتمثلة بعنصر ul وسوف نحتاج أيضًا إلى عناصر القائمة المتمثلة بعناصر li كما أننا سوف نحتاج إلى زر (button) ليعمل على فتح وإغلاق القائمة عند الضغط عليه. وسوف نحتاج في المثال الأول إلى شيء اضافي وهو عنصر div ليعمل كغشاء (overlay) يمنعنا من الضغط على أي مكان آخر في الصفحة طالما أنّ القائمة مفتوحة. ملاحظة: جميع الأيقونات المستخدمة في هذا الدرس هي من خدمة Font Awesome. شرح بعض الحسابات خلف CSS Transforms أفضل طريقة للشرح هنا ستكون باستعمال الصور بدلًا من الكلمات، لذلك سوف أبدأ بالمنطق الكامن وراء هذه الطريقة كما أننا سنقوم بتطبيق بعض الحسابات وبعد أن ننتهي من الشرح سوف نتوجه إلى جزء التكويد مما سيسمح لك بأن تعرف ما الذي تفعله كل واحدة من خصائص CSS التي سوف نستعملها. لنبدأ أولًا بتعريف ما هو المقصود بالزاوية المركزية. أنظر إلى الصورة التالية متبوعة بشرح بسيط: لنفرض أنك تريد توزيع عناصر القائمة على نصف دائرة كما هو الحال بالنسبة لما نريد إنشائه هنا، ولنفرض أيضًا أنّ لدينا 6 عناصر، إذًا كل زاوية سوف يكون لها زاوية مركزية بقيمة: 180 درجة / 6 = 30 درجة ماذا لو أردت توزيع العناصر على دائرة كاملة؟ بسيطة كل ما سنقوم بفعله هو التالي: 360 درجة / 6 = 60 درجة وهكذا دواليك. إذًا فكل ما يجب علينا فعله هو حساب الزاوية المركزية التي تناسبنا وبعدها نبدأ بتطبيق بعض الحسابات على خصائص CSS Transforms لنقوم بتطبيق هذه الزوايا عليها. وحتى يكون بامكاننا إنشاء زاوية مساوية للزوايا المركزية التي نريدها فإننا سوف نحتاج إلى حرف/تمييل (skew) العناصر وذلك باستخدام دالّة ()skew، وسوف تكون القيمة كالتالي: 90 درجة - x درجة ، بحيث تكون x هي الزاوية المركزية التي نريدها ولكن في هذه الحالة فإنّ جميع محتوى عناصر القائمة سوف تتم إمالتها وسوف تظهر بشكل غير مناسب، لذلك يجب علينا أن نقوم بتعديلها (أي نعمل لها unskew) حتى يظهر كل شيء بشكل جيد. يمكنك الدخول إلى هذا المثال لرؤية كيف يتم تطبيق التحويلات (transforms) إلى عناصر القائمة خطوة بخطوة حتى يتضح لك ما الذي سوف نقوم بفعله في الشيفرة البرمجية (ضع في الحسبان أن التسلسل الموجود في المثال قد يختلف بشكل بسيط عن الخطوات الفعلية التي سوف نتبعها في هذا الدرس). وهذه لقطات لكل خطوة سوف تراها في هذا المثال: الحالة الأولية: الخطوة الأولى: الخطوة الثانية: الخطوة الثالثة: الخطوة الرابعة: الخطوة الخامسة: الخطوة السادسة: إذًا هذا ما سوف نفعله: سوف نحتاج إلى موضعة عناصر القائمة بشكل مطلق (absolute positioning) داخل الحاوي الخاص بها. سوف نستعمل الخاصية transform-origin على كل عنصر وبالقيمة bottom right corner . بعد ذلك سوف نقوم بتحريك العناصر إلى الأعلى وإلى اليسار بشكل كافٍ حتى تتطابق مراكز التحريك الخاصة بها مع مركز العنصر الذي يحويها. سوف نقوم بتدوير العناصر في مواضعها باستخدام المعادلة التالية: كل عنصر له index بقيمة i سوف يتم تدويره بقيمة i*x حيث أن x كما سبق وذكرنا هي قيمة الزاوية المركزية. بعد ذلك نقوم بتمييلها (skew) للحصول على الزاوية المركزية التي نريدها (باستخدام المعادلة الموجودة في الأعلى). في مثالنا سوف يكون هناك 5 عناصر مما يعني وجود 5 زوايا مركزية وبالتالي سوف نقوم بتغطية الجزء العلوي فقط من الدائرة، واعتمادًا على المعادلات التي طرحناها سابقًا فسوف تكون الزاوية المركزية لكل عنصر هي 36 درجة (180 / 5) ولكننا سوف نجعل الزاوية المركزية تساوي 40 درجة مما يمنحنا منطقة أكبر قابلة للنقر، وبالتالي يكون مجموع الزوايا هو 40*5=200 وهو رقم أكبر من 180. في هذه الحالة سوف نحتاج إلى تدوير العناصر عكس عقارب الساعة بقيمة (200-180)/2 لنتأكد من أنها متوازنة على كلا الجانبين. قمنا إلى هذه النقطة بإنشاء الزوايا المركزية المناسبة، ولكن تمييل عناصر القائمة أدى أيضًا إلى تمييل المحتوى الذي بداخلها وبالتالي تشويهه، لذلك سوف نحتاج إلى تطبيق قاعدة رياضية أخيرة حتى نتأكد من ظهور المحتوى بشكل سليم وغير مشوه، وهذه القاعدة هي: نقوم بتمييل عناصر a الموجودة داخل عناصر القائمة وذلك بتطبيق قيمة معاكسة للقيمة المستخدمة لتمييل عناصر القائمة وبعد ذلك نقوم بتدويرها بالقيمة: -[90 - (x/2)] (لاحظ أن القيمة سالبة) ، مرة أخرى x هي الزاوية المركزية إذًا بما أن الزاوية المركزية هي 40 درجة فإننا سوف نحتاج إلى تمييل العناصر aبالقيمة -40 درجة وتدويرها بالقيمة -70 درجة (90 - (40/2)). سوف يتم موضعة عناصر a بشكل مطلق داخل الحاوي الخاص بها (الحاوي هنا هي عناصر القائمة) وسوف يتم إعطاء عناصر القائمة الخاصية overflow: hidden مما يعني أنّه سوف يتم قطع جزء من كل عنصر من عناصر a، وحتى نتأكد بأنّ محتوى العناصر (سواء كانت نص أو أيقونة) يبقى ضمن المحتوى الظاهر منها فإننا سوف نستعمل الخاصية text-align: center. وهذه هي كل الحسابات التي سوف نحتاجها إلى الآن. تبقى علينا الآن أن نقوم باستعمال تنسيقات CSS المناسبة حتى يصبح كل شيء بشكله المناسب. تنسيقات CSS سوف نقوم أولًا بتنسيق المثال الأول. سوف نستخدم Modernizr حتى نستطيع تحديد المتصفحات التي تدعم CSS Transforms والمتصفحات التي لا تدعمها ونقوم بتوفير fallback للمتصفحات القديمة التي لا تدعمها. لنبدأ أولًا بتنسيق العنصر الذي سوف يحتوي على القائمة ، بحيث سوف يكون ثابت إلى الأسفل ومتوسط للصفحة وسوف يكون متقلصًا/مخفيًا ويظهر/يتمدد عندما يتم النقر على الزر. .csstransforms .cn-wrapper { font-size:1em; width: 26em; height: 26em; overflow: hidden; position: fixed; z-index: 10; bottom: -13em; left: 50%; border-radius: 50%; margin-left: -13em; transform: scale(0.1); transition: all .3s ease; } /* class applied to the container via JavaScript that will scale the navigation up */ .csstransforms .opened-nav { border-radius: 50%; transform: scale(1); } سوف نقوم كذلك بتنسيق الزر الذي سوف يفتح ويغلق القائمة: .cn-button { border:none; background:none; color: white; text-align: Center; font-size: 1.5em; padding-bottom: 1em; height: 3.5em; width: 3.5em; background-color: #111; position: fixed; left: 50%; margin-left: -1.75em; bottom: -1.75em; border-radius: 50%; cursor: pointer; z-index: 11 } .cn-button:hover, .cn-button:active, .cn-button:focus{ background-color: #222; } عندما يتم فتح القائمة فإنه سوف يظهر غطاء/غشاء شفاف يغطي الصفحة، وهذه هي التنسيقات الخاصة به: .cn-overlay{ width:100%; height:100%; background-color: rgba(0,0,0,0.6); position:fixed; top:0; left:0; bottom:0; right:0; opacity:0; transition: all .3s ease; z-index:2; pointer-events:none; } /* Class added to the overlay via JavaScript to show it when navigation is open */ .cn-overlay.on-overlay{ pointer-events:auto; opacity:1; } سوف نقوم الآن بتنسيق عناصر القائمة وعناصر a الموجودة بداخلها وذلك بتطبيق المنطق والالحسابات التي تحدثنا عنها في البداية: .csstransforms .cn-wrapper li { position: absolute; font-size: 1.5em; width: 10em; height: 10em; transform-origin: 100% 100%; o verflow: hidden; left: 50%; top: 50%; margin-top: -1.3em; margin-left: -10em; transition: border .3s ease; } .csstransforms .cn-wrapper li a { display: block; font-size: 1.18em; height: 14.5em; width: 14.5em; position: absolute; bottom: -7.25em; right: -7.25em; border-radius: 50%; text-decoration: none; color: #fff; padding-top: 1.8em; text-align: center; transform: skew(-50deg) rotate(-70deg) scale(1); transition: opacity 0.3s, color 0.3s; } .csstransforms .cn-wrapper li a span { font-size: 1.1em; opacity: 0.7; } /* for a central angle x, the list items must be skewed by 90-x degrees in our case x=40deg so skew angle is 50deg items should be rotated by x, minus (sum of angles - 180)2s (for this demo) */ .csstransforms .cn-wrapper li:first-child { transform: rotate(-10deg) skew(50deg); } .csstransforms .cn-wrapper li:nth-child(2) { transform: rotate(30deg) skew(50deg); } .csstransforms .cn-wrapper li:nth-child(3) { transform: rotate(70deg) skew(50deg) } .csstransforms .cn-wrapper li:nth-child(4) { transform: rotate(110deg) skew(50deg); } .csstransforms .cn-wrapper li:nth-child(5) { transform: rotate(150deg) skew(50deg); } .csstransforms .cn-wrapper li:nth-child(odd) a { background-color: #a11313; background-color: hsla(0, 88%, 63%, 1); } .csstransforms .cn-wrapper li:nth-child(even) a { background-color: #a61414; background-color: hsla(0, 88%, 65%, 1); } /* active style */ .csstransforms .cn-wrapper li.active a { background-color: #b31515; background-color: hsla(0, 88%, 70%, 1); } /* hover style */ .csstransforms .cn-wrapper li:not(.active) a:hover, .csstransforms .cn-wrapper li:not(.active) a:active, .csstransforms .cn-wrapper li:not(.active) a:focus { background-color: #b31515; background-color: hsla(0, 88%, 70%, 1); } .csstransforms .cn-wrapper li:not(.active) a:focus { position: fixed; /* fix the "displacement" bug in webkit browsers when using tab key */ } سوف نقوم بتوفير fallback بسيط للمتصفحات التي لا تدعم CSS Transforms. .no-csstransforms .cn-wrapper{ font-size:1em; height:5em; width:25.15em; bottom:0; margin-left: -12.5em; overflow: hidden; position: fixed; z-index: 10; left:50%; border:1px solid #ddd; } .no-csstransforms .cn-button{ display:none; } .no-csstransforms .cn-wrapper li{ position:static; float:left; font-size:1em; height:5em; width:5em; background-color: #eee; text-align:center; line-height:5em; } .no-csstransforms .cn-wrapper li a{ display:block; width:100%; height:100%; text-decoration:none; color:inherit; font-size:1.3em; border-right: 1px solid #ddd; } .no-csstransforms .cn-wrapper li a:last-child{ border:none; } .no-csstransforms .cn-wrapper li a:hover, .no-csstransforms .cn-wrapper li a:active, .no-csstransforms .cn-wrapper li a:focus{ background-color: white; } .no-csstransforms .cn-wrapper li.active a { background-color: #6F325C; color: #fff; } وبالطبع فنحن نريد أن تكون القائمة متجاوبة مع جميع الأجهزة وتتقلص للشاشات الصغيرة: @media screen and (max-width:480px){ .csstransforms .cn-wrapper{ font-size:.68em; } .cn-button{ font-size:1em; } .csstransforms .cn-wrapper li { font-size:1.52em; } } @media screen and (max-width:320px){ .no-csstransforms .cn-wrapper{ width:15.15px; margin-left: -7.5em; } .no-csstransforms .cn-wrapper li{ height:3em; width:3em; } } هذا كان كل شيء يخص المثال الأول. دعونا الآن ننتقل لتنسيق المثال الثاني. في المثال الثاني سوف تكون القائمة مختلفة قليلًا عن القائمة في المثال الأول، ولكن كل المنطق والحسابات التي يخص القائمة الأولى سينطبق على هذه القائمة مع وجود ثلاثة اختلافات. لن نقوم بالرجوع وتوضيح كل شيء مرة أخرى وإنما سوف نكتفي بالتحدث عن الاختلافات الثلاثة فقط. دعونا نأخذ نفس المثال الموجود في الأعلى ونقوم بتغيير خاصية CSS واحدة فقط ونرى ما التغيير الذي سوف تصنعه على شكل عناصر القائمة. سوف نقوم بتطبيق تدرج لوني دائري على عناصر a مع لون خلفية شفاف، وسوف تظهر النتيجة كالتالي: سوف نقوم الآن بإضافة بعض المسافة بين عناصر القائمة وذلك بتغيير درجة الدوران لكل عنصر. سوف نقوم كذلك بإزالة لون الخلفية لعناصر القائمة وللحاوي وللحدود وسوف نقوم بتقليص قيمة الخاصية padding-top لعناصر a حتى نجعل الأيقونات متوسطة بشكل مثالي داخل العناصر. النتيجة النهائية ستكون كما في الصورة التالية: يمكنك أن ترى بأنّ القائمة بدأت تبدو بمظهر مختلف، وبقي شيء واحد مهم يجب أن نقوم به. ففي حالة بقاء التنسيقات كما هي عليه في الوقت الحالي فإنّ المناطق القابلة للنقر الخاصة بعناصر a ستكون أكبر مما نريده، فما نريده هو أن يكون الجزء الملون من القائمة هو فقط القابل للنقر. الصورة التالية توضح الجزء الزائد القابل للنقر والذي لا نريده: عندما تقوم بوضع مؤشر الفأرة فوق المنطقة الحمراء الموضحة في الصورة الموجودة في الأعلى فإنّه سيتم تفعيل حالة الـhover الخاصة بعناصر a وهو شيء طبيعي الحدوث ولكننا لا نريده لأننا نريد أن تظهر العناصر وكأنها هي فقط الجزء البنفسجي، وبالتالي سوف نحتاج إلى منع تفعيل أحداث الفأرة على الجزء الملون باللون الأحمر. لذلك ما سنقوم به هو استخدام pseudo-element (سوف تفي بالغرض لأننا لا نريد استعمال وسم فارغ) ليعمل كغطاء/غشاء يقوم بتغطية منطقة اللون الأحمر وبالتالي نمنع تفعيل أحداث الماوس على هذه المنطقة. إذًا سوف نقوم بتطبيق الخطوات الثلاثة التي ذكرناها مع تغيير بعض التنسيقات (كاللون والحجم) بالنسبة للقائمة ولعناصر القائمة ليظهر كل شيء كما في الصورة: .csstransforms .cn-wrapper { position: absolute; top: 100%; left: 50%; z-index: 10; margin-top: -13em; margin-left: -13.5em; width: 27em; height: 27em; border-radius: 50%; background: transparent; opacity: 0; transition: all .3s ease 0.3s; transform: scale(0.1); pointer-events: none; overflow: hidden; } /*cover to prevent extra space of anchors from being clickable*/ .csstransforms .cn-wrapper:after{ color: transparent; content:"."; display:block; font-size:2em; width:6.2em; height:6.2em; position: absolute; left: 50%; margin-left: -3.1em; top:50%; margin-top: -3.1em; border-radius: 50%; z-index:10; } .csstransforms .cn-wrapper li { position: absolute; top: 50%; left: 50%; overflow: hidden; margin-top: -1.3em; margin-left: -10em; width: 10em; height: 10em; font-size: 1.5em; transition: all .3s ease; transform: rotate(76deg) skew(60deg); transform-origin: 100% 100%; pointer-events: none; } .csstransforms .cn-wrapper li a { position: absolute; position: fixed; /* fix the "displacement" bug in webkit browsers when using tab key */ right: -7.25em; bottom: -7.25em; display: block; width: 14.5em; height: 14.5em; border-radius: 50%; background: #429a67; background: radial-gradient(transparent 35%, #429a67 35%); color: #fff; text-align: center; text-decoration: none; font-size: 1.2em; line-height: 2; transition: all .3s ease; transform: skew(-60deg) rotate(-75deg) scale(1); pointer-events: auto; } .csstransforms .cn-wrapper li a span { position: relative; top: 1.8em; display: block; font-size: .5em; font-weight: 700; text-transform: uppercase; } .csstransforms .cn-wrapper li a:hover, .csstransforms .cn-wrapper li a:active, .csstransforms .cn-wrapper li a:focus { background: radial-gradient(transparent 35%, #449e6a 35%); } نريد للعناصر في المثال الثاني أن تظهر بتأثير شبيه لحركة المروحة عندما نقوم بفتح القائمة (يمكنك الذهاب إلى المثال الثاني لترى ما الذي أقصده). وللحصول على هذا التأثير فإننا قمنا بموضعة العناصر بنفس المكان وبنفس التمييل والتدوير بقيمة (rotate(76deg) skew(60deg. يمكننا باستعمال تأخيرات التنقل (transition delays) بأن نسمح للعناصر بأن تتمدد/تتفرق عن بعضها بعد أن يظهر الحاوي ويتمدد. وعندما نقوم بغلق القائمة فسوف ننتظر حتى تعود عناصر القائمة قبل أن نقوم بتقليص الحاوي وإخفائه. عند الضغط على زر الفتح فسوف نقوم بإبعاد عناصر القائمة عن بعضها وذلك عن طريق تدوير كل عنصر إلى مكانه النهائي في الدائرة. .csstransforms .opened-nav { border-radius: 50%; opacity: 1; transition: all .3s ease; transform: scale(1); pointer-events: auto; } .csstransforms .opened-nav li { transition: all .3s ease .3s; } .csstransforms .opened-nav li:first-child { transform: rotate(-20deg) skew(60deg); } .csstransforms .opened-nav li:nth-child(2) { transform: rotate(12deg) skew(60deg); } .csstransforms .opened-nav li:nth-child(3) { transform: rotate(44deg) skew(60deg); } .csstransforms .opened-nav li:nth-child(4) { transform: rotate(76deg) skew(60deg); } .csstransforms .opened-nav li:nth-child(5) { transform: rotate(108deg) skew(60deg); } .csstransforms .opened-nav li:nth-child(6) { transform: rotate(140deg) skew(60deg); } .csstransforms .opened-nav li:nth-child(7) { transform: rotate(172deg) skew(60deg); } وبالطبع سوف نوفر fallback بسيط للمتصفحات غير الداعمة: .no-csstransforms .cn-wrapper{ margin:10em auto; overflow:hidden; text-align:center; padding:1em; } .no-csstransforms .cn-wrapper ul{ display:inline-block; } .no-csstransforms li{ font-size:1em; width:5em; height:5em; float:left; line-height:5em; text-align:center; background-color: #fff; } .no-csstransforms li a{ display:block; height:100%; width:100%; text-decoration: none; color: inherit; } .no-csstransforms .cn-wrapper li a:hover, .no-csstransforms .cn-wrapper li a:active, .no-csstransforms .cn-wrapper li a:focus{ background-color: #f8f8f8; } .no-csstransforms .cn-wrapper li.active a { background-color: #6F325C; color: #fff; } .no-csstransforms .cn-button{ display:none; } وكذلك سوف نجعل القائمة متجاوبة وذلك بتقليصها للشاشات الصغيرة: @media only screen and (max-width: 620px) { .no-csstransforms li{ width:4em; height:4em; line-height:4em; } } @media only screen and (max-width: 500px) { .no-ccstransforms .cn-wrapper{ padding:.5em; } .no-csstransforms .cn-wrapper li{ font-size:.9em; width:4em; height:4em; line-height:4em; } } @media only screen and (max-width: 480px) { .csstransforms .cn-wrapper{ font-size: .68em; } .cn-button{ font-size:1em; } } @media only screen and (max-width:420px){ .no-csstransforms .cn-wrapper li{ width:100%; height:3em; line-height:3em; } } هذا كان كل ما يخص تنسيقات CSS. دعونا الآن نرى ما الذي سوف نحتاج لعمله باستخدام الجافاسكربت. بعض الجافاسكربت لن نستخدم أي إطار عمل للجافاسكربت هنا ولكننا سوف نستخدم Classie.js لإضافة وإزالة الفئات (classes). وأما بالنسبة للمتصفحات التي لا تدعم addEventListener و removeEventListener فإننا سوف نستخدم EventListener polyfill. سوف نقوم بإضافة مدير أحداث (event handler) إلى الزر بحيث يتم فتح/اغلاق القائمة عند النقر عليه أو استخدام زر tab في لوحة المفاتيح (أي عند حدوث focus على العنصر). نريد أيضًا فيالمثال الأول أن يتم اغلاق القائمة عند النقر على أي مكان خارج القائمة. لنبدأ أولًا بالجافاسكربت الخاص بالمثال الأول: (function(){ var button = document.getElementById('cn-button'), wrapper = document.getElementById('cn-wrapper'), overlay = document.getElementById('cn-overlay'); //open and close menu when the button is clicked var open = false; button.addEventListener('click', handler, false); button.addEventListener('focus', handler, false); wrapper.addEventListener('click', cnhandle, false); function cnhandle(e){ e.stopPropagation(); } function handler(e){ if (!e) var e = window.event; e.stopPropagation(); //so that it doesn't trigger click event on document if(!open){ openNav(); } else{ closeNav(); } } function openNav(){ open = true; button.innerHTML = "-"; classie.add(overlay, 'on-overlay'); classie.add(wrapper, 'opened-nav'); } function closeNav(){ open = false; button.innerHTML = "+"; classie.remove(overlay, 'on-overlay'); classie.remove(wrapper, 'opened-nav'); } document.addEventListener('click', closeNav); })(); الجافاسكربت الخاص ب المثال الثاني مشابه للأولى نوعًا ما ولكن مع وجود بعض الاختلافات: (function(){ var button = document.getElementById('cn-button'), wrapper = document.getElementById('cn-wrapper'); //open and close menu when the button is clicked var open = false; button.addEventListener('click', handler, false); button.addEventListener('focus', handler, false); function handler(){ if(!open){ this.innerHTML = "Close"; classie.add(wrapper, 'opened-nav'); } else{ this.innerHTML = "Menu"; classie.remove(wrapper, 'opened-nav'); } open = !open; } function closeWrapper(){ classie.remove(wrapper, 'opened-nav'); } })(); خاتمة هذا كان كل شيء فيما يتعلق بهذا الدرس، أتمنى أن تكون قد استفدت منه وتعلمت شيئًا جديدًا. ترجمة -وبتصرّف- للمقال Building a Circular Navigation with CSS Transforms HTML/CSS لصاحبته Sara Soueidan.
  3. بعد أن تطرّقنا في هذه السّلسلة حول أساسيات تطوير قوالب ووردبريس إلى تحويل صفحة HTML إلى قالب ووردبريس ثم إلى كيفية إضافة Pagination (أو ما يُعرف بالتّصفيح) إليها، سنتطرّق اليوم إلى خاصّيّة أخرى لا تقل أهمّية. قوائم التنقّل (Navigation Menu) هي إحدى ميزات القوالب، توفّر ووردبريس طريقة سهلة للتحكم بالقوائم المخصصة للقالب من داخل لوحة تحكم ووردبريس، وكل ما تحتاجه هو إضافة بضعة أسطر برمجية لتضيف دعم القوائم في قالبك. فهرس السلسلة: مقدمة إلى تطوير قوالب ووردبريس: تحويل صفحة HTML إلى قالب ووردبريس التصفيح (Pagination) في قوالب ووردبريس إضافة قوائم التنقل (Navigation Menu) إلى قالب ووردبريس (هذا الدرس) صف وتسجيل ملفات Javascript و CSS في قوالب ووردبريس تسجيل القوائم بدايةً في ملف functions.php ضمن ملفات القالب نحتاج لإضافة دالّة تقوم بتسجيل أسماء القائمة (أو القوائم) التي تريد إضافتها. كالتالي: add_action('init', function() { register_nav_menu('our-custom-menu', 'القائمة الرئيسية'); }); بعد ذلك يمكن التأكد من صحة إضافة القائمة عن طريق الذهاب من لوحة التحكم إلى المظهر (Appearance) ثم القوائم (Menus)، ستظهر لدينا قائمة باسم القائمة الرئيسية في تبويب إدارة موضع القوائم. تأخذ دالّة register_nav_menu محدّدين هما: المكان (Location) والوصف (Description). محدّد المكان يستخدم كمعرّف للقائمة، حيث يتم طلب محتوى القائمة ضمن ملفات القالب عن طريق محدّد المكان (location) الذي قمنا بتعيينه أثناء تسجيل القائمة. في حالتنا قمنا بوضع قيمة المحدد هي: our-custom-menu. والوصف يتم استخدامه عند عرض القائمة في لوحة التحكم ليكون أنسب وأسهل للقراءة من محدد المكان، في حالتنا قمنا بوضع قيمة الوصف هي: القائمة الرئيسية. يمكننا تسجيل أكثر من قائمة في آن واحد عن طريق استخدام دالّة register_nav_menus التي تستخدم بشكل مشابه لدالّة register_nav_menu لكن المحدّدات تكون على شكل مصفوفة اسميّة (Associative Array)، كل عنصر في المصفوفة يمثّل قائمة واحدة بحيث يكون مفتاح العنصر هو محدّد المكان وقيمة العنصر هي محدّد الوصف. في قالبنا لا نحتاج سوى لقائمة واحدة، في ما يلي كيفية تسجيل أكثر من قائمة معًا: add_action('init', function() { register_nav_menus([ 'our-custom-menu' => 'القائمة الرئيسية', 'our-second-menu' => 'القائمة الفرعية', ]); }); كما ننوه إلى وجود دالّة معاكسة لدالّة تسجيل القوائم هي unregister_nav_menu لكننا لن نتطرّق إليها الآن. إظهار القائمة في القالب الخطوة الأخيرة ضمن القالب هي عرضه في المكان المناسب. في القالب الذي نستعمله نجد أن موقع القوائم أصبح في ملف header.php، في السطر 30 من الملف نجد وسم <section class="top-bar-section">، نريد أن نضع القائمة بدلاً من وسم <ul> الموجود بداخله. نقوم بحذف وسم <ul> مع محتواه، ثم نستخدم السطر البرمجيّ التالي لعرض القائمة: <?php wp_nav_menu(['theme_location' => 'our-custom-menu']); ?> تقبل دالّة wp_nav_menu مُحدداً واحداً هو مصفوفة تحوي عددًا من الإعدادات، الإعداد الوحيد الضروري هو theme_location ويتم استخدامه كما في السطر البرمجي السابق. يمثل هذا المحدّد قيمة محدّد المكان السابقة التي استخدمناها أثناء تسجيل قائمة جديدة والتي كانت: our-custom-menu. في حال لم يتم إدخال هذا المحدّد تقوم ووردبريس باستخدام قيمة إعداد menu (سنأتي إليه في الفقرة التالية)، وإن لم تجد قيمة فسيتم عرض أول قائمة غير فارغة تجدها ووردبريس، وفي حال عدم وجود أي قوائم غير فارغة وعدم تمرير محدّد المكان فلا يتم عرض شيء. إن ألقينا نظرة على القالب من المتصفح سنجد أن شكل عناصر القائمة أصبح مختلف قليلاً عن الشكل الذي كان عليه، وذلك ﻷن الدالّة تقوم بإضافة وسم <div> محيط بوسوم القائمة. في الفقرة التالية سنتعرف على بقية الإعدادات التي يمكن أن نستخدمها مع دالّة wp_nav_menu والتي ستمكننا من إظهار القائمة على الشكل الأنسب. إعدادات دالة wp_nav_menu كما قلنا من قبل فإن دالّة wp_nav_menu تأخذ محدّداً واحداً هو مصفوفة تحوي مجموعة إعدادات، المبرمج ليس مضطراً لإدخال جميع الإعدادات، يمكنه إدخال بعضها والباقي ستقوم ووردبريس بمعالجته وإسناد قيمته الافتراضية. الإعدادات بشكل كامل هي: <?php $defaults = array( 'theme_location' => '', 'menu' => '', 'container' => 'div', 'container_class' => '', 'container_id' => '', 'menu_class' => 'menu', 'menu_id' => '', 'echo' => true, 'fallback_cb' => 'wp_page_menu', 'before' => '', 'after' => '', 'link_before' => '', 'link_after' => '', 'items_wrap' => '<ul id="%1$s" class="%2$s">%3$s</ul>', 'depth' => 0, 'walker' => '' ); wp_nav_menu( $defaults ); ?> theme_location مكان القائمة ضمن القالب، كما تم تحديده أثناء تسجيل القائمة باستخدام دالّة register_nav_menu، ليكون بإمكان المستخدم تحديد القائمة المطلوبة للمكان الذي تم تسجيله (دون تقييد المستخدم بقائمة واحدة). القيمة الافتراضية: '' (سلسلة نصية فارغة) menu القائمة المطلوب عرضها، تقبل قيمة المعرّف الرقمي (ID)، أو الاسم اللطيف (slug)، أو الاسم الخاص بالقائمة (وليس مكان القائمة ضمن القالب). القيمة الافتراضية: '' (سلسلة نصية فارغة) container لتحديد إن كان مطلوبًا من ووردبريس إحاطة وسم <ul> بوسم آخر أم لا، القيمة المسموحة هي div أو nav، وفي حال عدم الرغبة بإحاطة القائمة بوسم نجعل القيمة false. القيمة الافتراضية: 'div' container_class الصنف الخاص بوسم html المحيط بالقائمة، بشكل افتراضي يأخذ الصنف الشكل: menu-{menu slug}-container حيث يكون {menu slug} هو الاسم اللطيف للقائمة. القيمة الافتراضية: '' (سلسلة نصية فارغة) container_id معرّف CSS (ID) الذي يتم تطبيقه على الوسم المحيط (container). القيمة الافتراضية: '' (سلسلة نصية فارغة) menu_class الصنف الذي يتم تطبيقه على وسم القائمة <ul>، يمكن أن يتم وضع أكثر من صنف يتم الفصل بينهم بفراغات (space). القيمة الافتراضية: 'menu' menu_id معرّف (ID) CSS الذي يتم تطبيقه على وسم القائمة <ul>. بشكل افتراضي تكون قيمته: menu-{menu slug} حيث {menu slug} هو الاسم اللطيف للقائمة؛ في حال حدوث تكرار بالاسم يتم إضافة إشارة - مع رقم مميز يبدأ من 1 ويزيد عند كل تكرار، مثلًا: menu-{menu slug}-1، menu-{menu slug}-2، إلخ. القيمة الافتراضية: '' (سلسلة نصية فارغة) echo فيما إن كنا نريد إظهار القائمة مباشرة في مكان استخدام دالّة wp_nav_menu أو نريد إرجاعها (return). القيمة الافتراضية: true fallback_cb دالّة ليتم استخدامها في حال لم تكن القائمة موجودة، نضع قيمتها false في حال لم نكن نريد استخدام دالّة. ويتم تمرير محدّد $args للدالّة التي يتم استخدامها. القيمة الافتراضية: 'wp_page_menu' before إظهار نصّ قبل وسم <a>. القيمة الافتراضية: '' (سلسلة نصية فارغة) after إظهار نصّ بعد وسم </a>. القيمة الافتراضية: '' (سلسلة نصية فارغة) link_before إظهار نصّ قبل نصّ الرابط. القيمة الافتراضية: '' (سلسلة نصية فارغة) link_after إظهار نصّ بعد نصّ الرابط. القيمة الافتراضية: '' (سلسلة نصية فارغة) items_wrap يتم تفسيرها بنفس الطريقة التي يتم تفسير محدّد الهيئة (format) لدالّة sprintf. يحدث تعاون بين المحددات الأخرى عن طريق رموز رقمية. %1$s تُستبدل بقيمة محدد menu_id، %2$s تُستبدل بقيمة محدد menu_class، و %3$s تُستبدل بقيمة عناصر القائمة (وسوم <li>). إن تم استبعاد أي رمز رقمي من هذا المحدّد، سيتم استبعاد المحدّد المرتبط به من وسوم القائمة. القيمة الافتراضية: '<ul id="%1$s" class="%2$s">%3$s</ul>' depth يمثل عدد المستويات الهرمية التي سيتم استخدامها، حيث رقم 0 يعني جميع المستويات. ويتم استخدام قيمة -1 لتحويل جميع المستويات إلى مستوى واحد فقط. القيمة الافتراضية: 0 walker يتم تمرير عنصر هو نسخة من صنف Walker_Nav_Menu أو من صنف يرث من ذلك الصنف. الهدف من هذا المحدد هو التحكم بشكل كامل بالأصناف (classes) والمحدّدات (IDs) ووسوم HTML للقائمة. يمكن العودة لتوثيق WordPress للاطلاع على المثال المقدم القيمة الافتراضية: '' (سلسلة نصية فارغة) تحسين ظهور القائمة في القالب بعد أن تعرّفنا على إعدادات إظهار القائمة، دعونا نقوم بتعديلها في قالبنا لتصبح مناسبة أكثر. إن شاهدنا مصدر HTML للصفحة الرئيسية من المتصفح، نجد أننا نحتاج لإزالة الوسم المحيط بالقائمة (container)، ونحتاج لإضافة صنف right لوسم <ul> المحيط بعناصر القائمة. يمكننا تعديل السطر البرمجي في ملف header.php ليصبح: <?php wp_nav_menu([ 'theme_location' => 'our-custom-menu', 'container' => false, 'menu_class' => 'right', ]); ?> قمنا بجعل قيمة الوسم المحيط (container) تساوي false ﻷننا لا نريد إحاطة القائمة بأي وسم، فنحن من البداية نقوم بإحاطة القائمة بوسم <section> في قالب HTML الذي نستخدمه. وقمنا أيضًا بإضافة قيمة محدد menu_class لتساوي: right، ليتم إضافة صنف right لوسم القائمة <ul> ليظهر بشكل جيّد. بهذا نكون قد جعلنا القائمة تظهر بشكل مرن، ونعطي المستخدم إمكانية أكبر لاختيار ما يناسبه من عناصر للقائمة من خلال لوحة التحكم، وبنفس الوقت جعلنا القائمة التي يختارها المستخدم تظهر بأفضل شكل ضمن القالب الذي نعمل عليه. الشريط الجانبي الأشرطة الجانبية (Sidebars) هي إحدى ميزات القوالب، هو بشكل بسيط عمود شاقولي يقوم القالب بتزويده لعرض معلومات مختلفة عن المحتوى الأساسي للموقع، تقوم الأشرطة الجانبية بعرض ودجات/مربعات (widgets) يقوم مدير المدونة بالتحكم بها. التعامل مع الشريط الجانبي يشبه إلى حدّ كبير التعامل مع القوائم. تسجيل شريط جانبي لنقم معاً بإضافة ما يلي إلى ملف functions.php لتعريف شريط جانبيّ جديد: add_action('widgets_init', function() { register_sidebar(); }); إن قمنا بزيارة لوحة التحكم، نجد أن هناك عنصراً جديداً في قائمة المظهر (Appearance) هو الودجات (Widgets)، بداخله يظهر لنا الشريط الجانبي الجديد بعنوان الشريط الجانبي 1، إن قمنا بإضافة شريط جانبي آخر سيأخذ نفس الاسم لكن بزيادة الرقم بمقدار واحد. والسبب أننا عندما قمنا بتسجيل الشريط الجانبي لم نحدد له اسماً أو معرّفاً. سنقوم بهذا الآن بعد أن نتعرف على إعدادات هذه الدالّة. إعدادات دالّة register_sidebar الإعدادات الافتراضية: $args = array( 'name' => sprintf( __( 'Sidebar %d' ), $i ), 'id' => "sidebar-$i", 'description' => '', 'class' => '', 'before_widget' => '<li id="%1$s" class="widget %2$s">', 'after_widget' => "</li>\n", 'before_title' => '<h2 class="widgettitle">', 'after_title' => "</h2>\n", ); شرح الإعدادات: name اسم الشريط الجانبي (القيمة الافتراضية هي ترجمة كلمة ‘Sidebar’ مع معرّف رقميّ). id معرّف الشريط الجانبي - يجب أن يكون بأحرف صغيرة (lowercase), دون فراغات (القيمة الافتراضية هي معرّف رقمية يتم زيادته تلقائياً ). description وصف نصّي لماهيّة/مكان الشريط الجانبي. يظهر في واجهة إدارجة الودجات في لوحة التحكم. (القيمة الافتراضية: فارغة) class صنف CSS ليتم إسناده للشريط الجانبي في صفحة إدارة الودجات، ولن يتم استخدام هذا الصنف في القالب. ملاحظة: سيتم إضافة كلمة “sidebar” إلى قيمة الصنف. مثلاً: إن وضعنا اسم الصنف: tal ستكون قيمة الصنف هي: sidebar-tal. (القيمة الافتراضية: فارغة). before_widget وسم/وسوم HTML ليتم وضعها قبل كل واحد من الودجات (widget) (القيمة الافتراضية: ‘<li id="%1$s" class="widget %2$s">‘). ملاحظة: يتم استخدام دالّة sprintf لاستبدال المتحولات. after_widget وسم/وسوم HTML ليتم وضعها بعد كل واحد من الودجات (widget) (القيمة الافتراضية: '\n'). before_title وسم/وسوم HTML ليتم وضعها قبل كل عنوان (القيمة الافتراضية: <h2 class="widgettitle">). after_title وسم/وسوم HTML ليتم وضعها بعد كل عنوان (القيمة الافتراضية: “</h2>\n“). عرض الشريط الجانبي في القالب نتوجه إلى ملف sidebar.php، ونقوم بتعديله ليصبح كالتالي: <div class="large-4 columns sidebar"> <?php dynamic_sidebar(); ?> </div> قمنا باستبدال النصّ الموجود مسبقاً “Sidebar” بدالّة ()dynamic_sidebar التي وظيفتها عرض محتويات الشريط الجانبي في المكان المحدد. يمكن أن نمرّر قيمة واحدة لتلك الدالّة إما أن تكون اسم (name) أو معرّف (ID) الشريط الجانبي. وفي حال عدم تمرير أي قيمة يتم عرض الشريط الجانبي الأول. تخصيص الشريط الجانبي كما لاحظنا فشكل ودجات الشريط الجانبي غير مقبولة، لنقم معًا بتحسين مظهرها عن طريق إحاطة كل واحدة من الودجات (widgets) بوسم <div class="card"> الذي كان موجودًا في ملف sidebar.php قبل استخدام دالّة عرض الشريط الجانبي. لنقم باستخدام إعدادات دالّة ()register_sidebar التي مرّت معنا في الفقرات السابقة، في ملف functions.php نقوم بتعديل الدالّة لتصبح: register_sidebar(['before_widget' => '<div class="card">', 'after_widget' => '</div>']); قمنا بتمرير إعدادَين فقط لإضافة وسم div قبل واحدة من الودجات وإضافة إغلاق الوسم بعد كل واحدة منها. بهذا نكون قد انتهينا من إضافة قائمة رئيسية وشريط جانبي إلى القالب، وتعلمنا معاً كيف يمكن تخصيص شكل القائمة والشريط الجانبي ليتناسب مع القالب بأفضل شكل ممكن.
  4. تتكوّن تطبيقات الأجهزة المحمولة عادةً من صفحات منفصلة يتنقّل بينها المستخدم لاستفادة من الإمكانيات التي يقدمها التطبيق. بالنسبة لتطبيقات أندرويد فإنّ زر الرجوع إلى الخلف يُعتبر أساسيًا في عمليّة التنقّل هذه. سنتعرّف في هذا الدرس من سلسلة تعلّم برمجة تطبيقات أندرويد باستخدام Xamarin.Forms على كيفيّة التنقّل بين صفحات التطبيق. سنتحدّث أولًا عن مفهوم التنقّل بين الصفحات في التطبيق الواحد، ثمّ سنتحدّث عن أنواع صفحات المحتوى المستخدمة في التنقّل وذلك عن طريق مثال عملي بسيط. مفهوم التنقّل بين صفحات التطبيق يشبه التنقّل بين صفحات التطبيق مبدأ عمل المكدّس Stack إلى حدّ كبير. والمكدّس كما هو معلوم هو بنية معطيات تدعم مفهوم LIFO (الذي يدخل أخيرًا يخرج أولًا). فعند الانتقال من الصفحة A إلى الصفحة B، تُدفع pushed الصفحة B إلى أعلى المكدّس مما يؤدّي إلى ظهورها أمام المستخدم. وكذلك الأمر عند الانتقال من الصفحة B إلى الصفحة C يتم دفع الصفحة C إلى المكدّس ليتم إظهارها إلى المستخدم. أمّا عندما نريد العودة إلى الصفحة A الأصلية فيجب عندها أن تُخرج popped الصفحة C من المكدّس فتصبح الصفحة B أعلى المكدّس (أي تظهر للمستخدم) ثم تُخرج الصفحة B من المكدّس فتصبح الصفحة A أعلى المكدّس (أي تظهر للمستخدم). انظر الشكل التالي لتوضيح هذه الفكرة: صفحات Modal و Modeless يحتوي على كل تطبيق على صفحة رئيسيّة main page (ستكون من الصنف NavigationPage) تُعتبر العقدة الرئيسيّة التي يمكن الوصول من خلالها إلى جميع الصفحات الأخرى مهما كان عددها ومستواها. كما تميّز Xamarin بين نوعين من صفحات المحتوى التي تُستَخدم ضمن بنية التنقّل هذه وهي: الصفحات الجامدة Modal Pages والصفحات غير الجامدة Modeless Pages. الفرق بين هذين النوعين بالنسبة لتطبيقات أندرويد بسيط. وهو أنّه في الصفحات من النوع Modal لن يتم عرض عنوان الصفحة في الأعلى كما سنرى في المثال بعد قليل. أمّا في الصفحة من النوع Modeless فسيتم عنوان الصفحة في الأعلى في حال تمّ تحديده باستخدام الخاصيّة Title لصفحة المحتوى. لمعاينة الفرق بين هذه الأنواع لننشئ تطبيق عملي بسيط يوضّح هذا الأمر. ابدأ بإنشاء مشروع جديد من النوع Blank App (Xamarin.Forms Portable) وسمّه ModelessAndModal، ثم أبق فقط على المشروعين ModelessAndModal (Portable) و ModelessAndModal.Droid كما وسبق أن فعلنا في هذا الدرس. بعد ذلك سنضيف ثلاث صفحات محتوى عادية (Forms ContentPage) وهي: MainPage و ModalPage و ModelessPage. عدّل محتويات الملف MainPage ليكون مماثلًا لما يلي: 1 using Xamarin.Forms; 2 3 namespace ModelessAndModal 4 { 5 public class MainPage : ContentPage 6 { 7 public MainPage() 8 { 9 Title = "Main Page"; 10 11 Button gotoModelessButton = new Button 12 { 13 Text = "Go to Modeless Page", 14 HorizontalOptions = LayoutOptions.Center, 15 VerticalOptions = LayoutOptions.CenterAndExpand 16 }; 17 18 gotoModelessButton.Clicked += async (sender, args) => 19 { 20 await Navigation.PushAsync(new ModelessPage()); 21 }; 22 23 Button gotoModalButton = new Button 24 { 25 Text = "Go to Modal Page", 26 HorizontalOptions = LayoutOptions.Center, 27 VerticalOptions = LayoutOptions.CenterAndExpand 28 }; 29 30 gotoModalButton.Clicked += async (sender, args) => 31 { 32 await Navigation.PushModalAsync(new ModalPage()); 33 }; 34 35 Content = new StackLayout 36 { 37 Children = { gotoModelessButton, gotoModalButton } 38 }; 39 } 40 } 41 } ستعرض الصفحة الرئيسية MainPage زرّين فقط. الزر الأوًل هو gotoModelessButton ووظيفته إنشاء صفحة غير جامدة modeless والانتقال اليها. أمّا الزر الثاني فهو gotoModalButton ووظيفته إنشاء صفحة جامدة modal والانتقال إليها. بالنسبة للزر الأوّل gotoModelessButton انظر إلى الأسطر من 11 حتى 21: Button gotoModelessButton = new Button { Text = "Go to Modeless Page", HorizontalOptions = LayoutOptions.Center, VerticalOptions = LayoutOptions.CenterAndExpand }; gotoModelessButton.Clicked += async (sender, args) => { await Navigation.PushAsync(new ModelessPage()); }; ننشئ في البداية كائنًا من النوع Button ونسنده إلى المتغيّر gotoModelessButton ثمّ نعيّن معالج لحدث النقر Clicked وهو عبارة عن تعبير lambda بسيط يمثّل تابع يحتاج إلى وسيطين sender و e وهو مسبوق بالكلمة المحجوزة async كما هو واضح من الشيفرة السابقة. سبب وجود الكلمة async هو أنّنا سنستخدم استدعاءً غير متزامنًا ضمن معالج الحدث هذا وهو: await Navigation.PushAsync(new ModelessPage()); يعمل التابع PushAsync المُستدعى من الخاصيّة Navigation للصفحة الحالية على دفع صفحة جديدة ضمن المكدّس الخاص بالتنقّل بين الصفحات، بمعنى آخر، سيعمل هذا التابع على إظهار صفحة جديدة من النمط modeless. في السطر السابق سيتم إنشاء صفحة جديدة من النوع ModelessPage ومن ثمّ تمريرها إلى التابع PushAsync. أنصحك بمراجعة هذا الدرس لكي تنعش ذاكرتك حول موضوع الاستدعاءات غير المتزامنة. نفس الأمر سيجري تمامًا بالنسبة للزر الخاص بالانتقال إلى الصفحة الجامدة مع فارق بسيط. وهو أنّ الاستدعاء هذه المرة سيكون من خلال التابع PushModalAsync (السطر 32) وذلك للانتقال إلى صفحة جامدة (ستكون من الصنف ModalPage). في كلّ من الحالتين السابقتين كان من الممكن أن نجعل معالجي حدثي النقر ضمن تابعين مستقلين وليس كما هو الحال من خلال تعبيري Lambda. الأمر الجدير بالملاحظة بالنسبة للصنف MainPage أيضًا هو تعيين الخاصيّة Title (السطر 9). في الحقيقة لم يكن لهذه الخاصيّة أي معنى في جميع البرامج التي أنشأناها في هذه السلسلة حتى الآن. إذ تعيين هذه الخاصيّة من عدمه لن يُحدث أيّ فرق! الجديد هنا هو في كيفيّة إنشاء الصفحة MainPage بحد ذاتها، والتي سننشئها كم جرت العادة ضمن الصنف App. انتقل إلى الملف App.cs واحرص على أن تكون بانيته مطابقة لما يلي: public App() { // The root page of your application MainPage = new NavigationPage(new MainPage()); } لاحظ معي الأمر الجديد هنا. نحن لا ننشئ صفحة محتوى ونسندها للخاصيّة MainPage مباشرةً كما كنّا نفعل من قبل. إنّما ننشئ صفحة محتوى (في مثالنا هي من الصنف MainPage) ثم نمرّر هذه الصفحة كوسيط إلى بانية الصنف NavigationPage. أي أنّنا في الواقع ننشئ صفحة محتوى تدعم التنقّل navigation. وهذا ما سيجعل عنوان الصفحة الرئيسيّة المُعيّن باستخدام الخاصيّة Title يظهر أعلى الصفحة كما سنرى بعد قليل. يمكننا الآن أن نجرّب هذا التطبيق. نفّذ التطبيق لتحصل على شكل شبيه بما يلي: أوقف تنفيذ البرنامج لنبدأ بالمرحلة الأخيرة وهي تجهيز صفحتي المحتوى ModalPage و ModelessPage. انتقل إلى الملف ModalPage.cs واحرص على أن تكون محتوياته مطابقة لما يلي: using Xamarin.Forms; namespace ModelessAndModal { public class ModalPage : ContentPage { public ModalPage() { Title = "Modal Page"; Button goBackButton = new Button { Text = "Back to Main", HorizontalOptions = LayoutOptions.Center, VerticalOptions = LayoutOptions.Center }; goBackButton.Clicked += async (sender, args) => { await Navigation.PopModalAsync(); }; Content = goBackButton; } } } ثمّ انتقل إلى الملف ModelessPage.cs واحرص على أن تكون محتوياته كما يلي: using Xamarin.Forms; namespace ModelessAndModal { public class ModelessPage : ContentPage { public ModelessPage() { Title = "Modeless Page"; Button goBackButton = new Button { Text = "Back to Main", HorizontalOptions = LayoutOptions.Center, VerticalOptions = LayoutOptions.Center }; goBackButton.Clicked += async (sender, args) => { await Navigation.PopAsync(); }; Content = goBackButton; } } } محتويات كلّ من الصفحتين السابقتين متطابقة. فكل منهما يحتوي على زر اسمه goBackButton هدفه العودة إلى الصفحة السابقة (التي سببت ظهور الصفحة الحالية). هناك فرق بسيط وحيد بين معالجي حدثي النقر للزرين في الصفحتين السابقتين. بالنسبة للصفحة من النمط الجامد modal تم استخدام الاستدعاء غير المتزامن Navigation.PopModalAsync للعودة إلى الصفحة السابقة. أمّا في حالة الصفحة ذات النمط غير الجامد modeless فقد تمّ استخدام الاستدعاء غير المتزامن Navigation.PopAsync للعودة إلى الصفحة السابقة. ثمة فرق آخر عند تنفيذ البرنامج، وهو أنّه في حالة الانتقال من الصفحة الرئيسية إلى الصفحة ModelessPage (الصفحة غير الجامدة) سيظهر عنوان الصفحة في الأعلى مع سهم صغير يسمح لنا بالعودة إلى الصفحة السابقة. أمّا عند الانتقال من الصفحة الرئيسية إلى الصفحة ModePage (الصفحة الجامدة) فلن يظهر عنوان الصفحة أبدًا (رغم تعيين الخاصيّة Title لها)، والوسيلة الوحيدة للرجوع إلى الصفحة السابقة هي بنقر زر الرجوع الموجود ضمن الصفحة أو بنقر زر العودة إلى الوراء الذي يزوّدنا به نظام التشغيل. أجرِ بعض التجارب على التطبيق ولاحظ الفرق بين الصفحتين. الخلاصة تناولنا في هذا الدرس آلية التنقّل بين الصفحات في تطبيقات أندرويد، وهو موضوع مهمّ بالطبع. حيث تعرّفنا إلى الفرق بين الصفحات من النمط modal والنمط modeless. كما تعلّمنا كيفية إنشاء الصفحة الرئيسيّة التي تُعتبر حجر البناء الأساسي في عمليّة الانتقال بين الصفحات، وذلك من خلال إنشاء الصفحة الرئيسيّة لتكون من النوع NavigationPage.
  5. مقّدمة إذا كنتَ لا تمتلك خبرةً كبيرة في التعامل مع أنظمة لينكس، فربّما تكون مندهشًا من فكرة التحكّم بنظام التشغيل عبر سطر الأوامر. هنا، سنحاول شرح أساسيات فعلِ ذلك. لن يغطّي هذا الدّرس كل شيءٍ تحتاج معرفته للتعامل بفعالية مع نظام لينكس. ولكنّ من المفترض أن يعطيك أساسًا جيدًا للارتكاز عليه لكي تتمكن من استكشاف بقية الأمور بنفسك. سيُعطيك هذا الدّرس الأساسيات التي تحتاج أن تعرفها فقط قبل الانتقال إلى دليلٍ آخر. المتُطلّبات والأهداف من أجل المتابعة مع هذا الدّرس، ستحتاج إلى امتلاك الوصول إلى خادوم لينكس. إذا كنتَ تحتاج معلوماتٍ حول كيفية الاتصال بخادومك للمرّة الأولى، فيمكنك اتّباع هذا الدّرس حول كيفية الاتّصال بخادوم لينكس باستخدام SSH. قد تودُّ أيضًا امتلاك أساسيات فهم كيفية عمل الطرفيّة وكيف تبدو الأوامر في نظام لينكس. درسنا السابق هذا يغطّي أساسيات الطرفيّة، لذا فيجب عليك التحقق منه إذا كنتَ جديدًا على استخدام الطرفيّات. جميع المهام الموجودة في هذا الدّرس يُمكن إنجازها باستخدام حساب مستخدم عادي غير جذر (non-root) لا يمتلك صلاحياتٍ إدارية (حيث أننا لن نحتاجها). عندما تصبحُ جاهزًا للبدء، اتّصل بخادومك عبر SSH وتابع القراءة. دورة علوم الحاسوب دورة تدريبية متكاملة تضعك على بوابة الاحتراف في تعلم أساسيات البرمجة وعلوم الحاسوب اشترك الآن التنقّل والاستكشاف أهمّ المهارات الأساسية التي يجب عليك احترافها هي التنقّل في نظام الملفّات (filesystem) والحصول على فكرة عن الأشياء حولك. سنناقش الأدوات التي تسمح لك بفعل ذلك في هذا القسم. معرفة مكانك باستخدام الأمر pwd عندما تقوم بتسجيل الدخول إلى خادومك، فإنّه سيتم إرسالك عادةً إلى مجلّد المنزل (home directory) الخاص بحساب المستخدم الذي تستعمله. مجلّد المنزل هو عبارة عن مسارٍ مُعَدّ لمستخدمك لتخزين الملفات والمجلّدات. إنّه الموقع الذي تمتلك كامل السيطرة عليه في نظام الملفات. لمعرفة موقع مجلّد المنزل الخاص بك بالنسبة إلى بقيّة نظام الملفّات، يمكنك استخدام الأمر pwd. يقوم هذا الأمر بعرض المسار الذي نتواجدُ فيه حاليًا: pwd يجبُ أن تحصل على بعض المعلومات التي تبدو هكذا: /home/demo يتم تسمية مجلّد المنزل باسم المستخدم الذي يتبعُه، لذا ففي المثال السابق تلاحظ ما ستكون قيمة اسم مجلّد المنزل عندما تقوم بتسجيل الدخول إلى الخادوم باستخدام حسابٍ يُدعى demo . هذا المسار موجود داخل مجلد يُدعى /home ، والذي هو بدوره ضمن مسارٍ أعلى يدعى "الجذر (root)” ولكن يتم تمثيله بإشارة / واحدة. معرفة محتوى المجلّدات باستخدام ls الآن صرتَ تعرف كيفية عرض المسار الذي تتواجدُ فيه حاليًا، يمكننا الآن أن نعلّمك كيفية عرض محتويات مسارٍ معيّن. حاليًا، لا يمتلك مجلّد المنزل الخاص بك الذي رأيناه بالأعلى الكثير من الأمور بداخله لرؤيتها، لذلك سننتقل إلى مسارٍ أكثر امتلاءً بالملفّات لنستكشفه. قمّ بكتابة الأمر التالي في طرفيّتك للانتقال إلى هذا المسار (سنشرح تفاصيل الانتقال إلى مساراتٍ أخرى في القسم التالي). بعدها، سنستخدم الأمر pwd للتأكّد مما إذا كنّا قد انتقلنا بنجاح: cd /usr/share pwd /usr/share الآن أصبحنا في المسار الجديد، فلنلقي نظرةً على ما يوجد بداخله. لفعل هذا، يُمكننا استخدام الأمر ls: ls adduser groff pam-configs applications grub perl apport grub-gfxpayload-lists perl5 apps hal pixmaps apt i18n pkgconfig aptitude icons polkit-1 apt-xapian-index info popularity-contest . . . كما ترى، هناك العديد من العناصر بداخل هذا المسار. يمكننا إضافة بعض الأعلام الإضافية (flags) للأمر السابق للتعديل على سلوكه الافتراضي. كمثال، لسرد جميع المحتويات بشكلٍ أكثر تفصيلًا، سنستخدم العَلَم -l (اختصار لـlong output): ls -l total 440 drwxr-xr-x 2 root root 4096 Apr 17 2014 adduser drwxr-xr-x 2 root root 4096 Sep 24 19:11 applications drwxr-xr-x 6 root root 4096 Oct 9 18:16 apport drwxr-xr-x 3 root root 4096 Apr 17 2014 apps drwxr-xr-x 2 root root 4096 Oct 9 18:15 apt drwxr-xr-x 2 root root 4096 Apr 17 2014 aptitude drwxr-xr-x 4 root root 4096 Apr 17 2014 apt-xapian-index drwxr-xr-x 2 root root 4096 Apr 17 2014 awk . . . هذه الرؤيا تعطينا الكثير من المعلومات التي لم نعتد غالبًا على رؤيتها. تصف الكتلة الأولى (block) نوع الملفّ (إذا كان العمود الأول هو حرف "d” فحينها فالعنصر هو مجلّد، وإذا كان إشارة "-” فحينها يكون العنصر ملفًا عاديًا) والأذونات. يصفُ كلُّ عمودٍ منفصل مفصولٍ بمساحةٍ بيضاء عن غيره عددًا من المعلومات المختلفة مثل مالك الملفّ، المجموعة، حجم العنصر، تاريخ آخر تعديل واسم العنصر. سنقوم بتفصيل بعضٍ من هذه الأمور لاحقًا، ولكن الآن، يكفي أن تعرف أنّه بإمكانك عرض هذه المعلومات باستخدام عَلَم -l مع الأمر ls. لسرد جميع الملفّات بما في ذلك الملفّات المخفيّة، فسيجب عليك إضافة العَلَم -a . بما أنّه لا يوجد هناك ملفّات مخفية حقًا في المسار /usr/share ، فسيجب علينا الرجوع إلى مجلّد المنزل الخاص بنا لتجربة ذلك الأمر. يمكنك الرجوع إلى مجلّد المنزل عبر كتابة الأمر cd دون أي مُعطيات: cd ls -a . .. .bash_logout .bashrc .profile كما يمكنك أن ترى، هناك العديد من الملفّات المخفية في هذا المكان بالإضافة إلى كلٍ من . و .. واللذان يعتبران حرفين من نوعٍ خاص في نظام لينكس. ستجد غالبًا أنّه يتم تخزين ملفات الإعداد كملفات مخفيّة، كما في حالتنا هنا. بالنسبة إلى إشارة النقطة والنقطتين، فهما ليسا مجلّدين بالضبط، بل هما عبارة عن طريقة داخلية (method) للإشارة إلى مساراتٍ أخرى مرتبطة بالمسار الحالي. النقطة الواحدة تُشير إلى المسار الحالي، والنقطتان تشير إلى المسار الأبّ (parent directory) للمسار الحالي. سنشرح هذا الأمر في القسم التالي. التنقّل في نظام الملفّات باستخدام cd لقد قمنا بالانتقال بالفعل عبر مسارين مختلفين لتوضيح بعض خصائص ls في القسم السابق. فلنلقي جولةً أفضل على ذلك الأمر هنا. ابدأ عبر الرجوع إلى المسار /usr/share عبر كتابة التالي: cd /usr/share هذا مثالٌ لتغيير المسار الحالي عبر استخدام ما يعرف بالمسار المُطلق (absolute path). في لينكس، جميع الملفّات المجلّدات تقع تحت المسار الأكثر علوًا (top-most directory)، والذي ندعوه بمجلّد الجذر (root directory)، ولكن يُشار إليه بإشارة / واحدة. يقوم المسار المُطلق بتحديد موقع مجلّدٍ معيّن بالنسبة إلى هذا المسار الأكثر علوًا (مجلّد الجذر /). يسمحُ لنا هذا بالإشارة بطريقةٍ غير معقّدة إلى أيّ مكانٍ في نظام الملفّات. أيُّ مسارٍ مُطلق يجب أن يبدأ بإشارة / . الخيار البديل هو استخدام ما يُعرف بالمسارات المُرتبطة (relative paths). تقوم المسارات المُرتبطة بالإشارة إلى المسارات الموجودة على نظام الملفّات بالنسبة إلى المسار الحالي. هذه الطريقة عادةً تكون أسهل وأقصر بالنسبة إلى المسارات القريبة من المسار الحالي في شجرة الملفّات. يُمكن الإشارة إلى أيّ مسارٍ موجود ضمن المسار الحالي عبر تسميته دون الحاجة لإشارة / . يُمكننا الانتقال إلى المجلّد locale الموجود ضمن /usr/share (والذي هو مسارنا الحالي) عبر كتابة: cd locale يُمكننا أيضًا القفز خطوتين بدل خطوةٍ واحدة والانتقال إلى مسارٍ داخل مسارٍ آخر عبر توفير الجزء الثاني (الذي هو اسم المجلّد الثاني الذي سننتقل إليه) ووضعه بعد المسار الأول. كمثال، يُمكننا الوصول إلى المجلّد LC_MESSAGES الموجود داخل المجلّد en عبر كتابة الأمر التالي: cd en/LC_MESSAGES للرجوع إلى أعلى، وللانتقال إلى المسار الأب للمسار الحالي، يُمكننا استخدام حرف النقطتين الخاص .. الذي تحدّثنا عنه من قبل. كمثال، نحن الآن في المسار /usr/share/locale/en/LC_MESSAGES . للانتقال إلى أعلى بدرجةٍ واحدة، يمكننا أن نكتب: cd .. سيأخذنا هذا الأمر إلى المسار /usr/share/locale/en . من الاختصارات التي رأيتها بالسابق هو استخدام الأمر cd للرجوع إلى مجلّد المنزل الخاص بك بسرعة دون الحاجة لتوفير مساره المعيّن: cd pwd /home/demo لتعلّم المزيد حول كيفية استخدام هذه الأوامر الثلاثة، يمكنك مراجعة هذا الدّرس حول استكشاف نظام الملفّات في نظام لينكس. عرض الملفّات في القسم الأخير، تعلّمنا القليل حول كيفية التنقّل في نظام الملفّات. على الأرجح فإنّكَ رأيت بعض الملفّات أثناء استخدام أمر ls في المسارات السابقة. في هذا القسم، سنناقش طرقًا مختلفة يمكنك استخدامها لعرض الملفّات. على عكس الأنظمة الأخرى فإنّ نظام لينكس والأنظمة الأخرى الشبيهة بيونكس (Unix-like) تعتمدُ على استخدام الملفّات الصرفة (plain text files) في معظم أجزاء النظام. الطريقة الرئيسية التي نقوم من خلالها بعرض الملفّات هي عبر استخدام الأمر less. والذي ندعوه بـ"منشئ الصفحات (pager)”، لأنّه يسمح لنا بالتنقّل عبر صفحات ملفٍ معيّن، less هو عبارة عن تطبيقٍ سيستولي على شاشة الطرفيّة بأكملها أثناء عمله وسيبقى عاملًا إلى حين أن تقرر أنت إغلاقه. سنقوم بفتح الملفّ /etc/services ، والذي هو عبارة عن ملف إعداداتٍ يحتوي على معلومات الخدمات التي يعرفها النظام: less /etc/services سيتم فتح الملفّ في less ، مما يسمح لك بعرض جزءٍ من المستند بحيث يتوافق مع مساحة نافذة الطرفيّة: #Network services, Internet style # # Note that it is presently the policy of IANA to assign a single well-known # port number for both TCP and UDP; hence, officially ports have two entries # even if the protocol doesn't support UDP operations. # # Updated from http://www.iana.org/assignments/port-numbers and other # sources like http://www.freebsd.org/cgi/cvsweb.cgi/src/etc/services . # New ports will be added on request if they have been officially assigned # by IANA and used in the real-world or are needed by a debian package. # If you need a huge list of used numbers please install the nmap package. tcpmux 1/tcp # TCP port service multiplexer echo 7/tcp . . . للتمرير بين الصفحات، يُمكنك استخدام مفتاحيّ الأعلى والأسفل على لوحة مفاتيحك. للانتقال بصفحةٍ كاملة إلى الأسفل، يُمكنك إمّا أن تستخدم space bar أو زرّ "Page Down” على لوحة مفاتيحك، أو الاختصار CTRL + F. للرجوع إلى الأعلى، يمكنك إمّا أن تستخدم زرّ "Page Up” أو الاختصار CTRL + B. للبحث عن نصٍ معين في المستند، يمكنك كتابة إشارة / متبوعةً بالنصّ الذي تبحث عنه. كمثال، للبحث عن كلمة "mail”، سيجب علينا كتابة: /mail سيقوم الأمر السابق بالبحث عبر المستند عن كلمة "mail” ويتوقف عند أول نتيجةٍ متوفرة. للانتقال إلى نتيجةٍ أخرى، يمكنك استخدام مفتاح n الصغير (دون Caps Lock): n للرجوع إلى النتيجة السابقة، استخدام حرف N الكبير (مع Caps Lock): N عندما تريد الخروج من برنامج less، يمكنك ببساطة الضغط على حرف q: q صحيحٌ أننا قمنا بالتركيز على أداة less في هذا القسم، إلّا أنه يوجد العديد من الطرق الأخرى لعرض محتويات ملفٍّ ما. يقوم الأمر cat مثلًا بعرض محتويات الملفّ ويقوم بإرجاعك إلى موجّه الأوامر تلقائيًا. يقوم الأمر head افتراضيًا بعرض أول 10 سطورٍ من ملفٍ ما. أيضًا يقوم الأمر tail بعرض السطور الـ10 الأخيرة من ملفٍ ما. تقوم هذه الأوامر بعرض محتويات الملفّات بطريقة تجعلها مناسبة للاستخدام لنقلها عبر الأنابيب (piping) لبرامج أخرى. سنناقش هذا المفهوم في دليلٍ مستقبلي. جرّب الآن استخدام الأوامر السابقة لعرض محتويات الملفّ /etc/services . التّعامل مع الملفّات والمجلّدات تعلّمنا في القسم الأخير كيفية عرض الملفّات، في هذا القسم، سنقوم بتوضيح آلية التّعامل مع الملفّات والمجلّدات وإنشائها. إنشاء ملفّ باستخدام touch يمكن للعديد من الأوامر والبرامج أن تقوم بإنشاء الملفّات. الطريقة الأساسية لإنشاء الملفّات هي عبر الأمر touch. هذا الأمر سيقوم بإنشاء ملفٍ فارغ باستخدام اسم الملفّ المطلوب وموقعه المحدد. أولًا، يجب علينا التأكّد مما إذا كنّا في مجلّد المنزل الخاصّ بنا، بما أنّه المجلّد الذي نمتلكُ فيه صلاحيات حفظ الملفّات. فحينها يمكننا إنشاء ملفٍ يدعى file1 عبر كتابة: cd touch file1 الآن، إذا قمنا بعرض الملفّات الموجودة في مجلّد المنزل الخاصّ بنا، سنرى ملفّنا الجديد: ls file1 إذا استخدمنا هذا الأمر على ملفٍ موجود مسبقًا، فإنّه ببساطة سيتم تحديث وقت آخر تعديل على الملفّ الذي حاولنا إنشاءه (ولكن لن يتم الكتابة فوقه أو حذفه). هذا لن يفيدنا كثيرًا في مرحلتنا هذه. يمكننا أيضًا إنشاء أكثر من ملف في نفس الوقت. يمكننا أيضًا استخدام المسارات المُطلقة. كمثال، إذا كان اسم المستخدم الخاصّ بنا يدعى demo ، فحينها يمكننا كتابة: touch /home/demo/file2 /home/demo/file3 ls file1 file2 file3 إنشاء المسارات باستخدام mkdir هذا الأمر شبيهٌ بالأمر touch، يسمحُ لنا الأمر mkdir بإنشاء مساراتٍ (مجلّدات) جديدة فارغة. كمثال، لإنشاء مجلّد جديد ضمن مجلّد المنزل الخاص بنا ولندعوه test ، يمكننا ببساطة كتابة: cd mkdir test يمكننا أيضًا إنشاء مجلّدٍ داخل مجلّد test ولندعوه example مثلًا عبر كتابة: mkdir test/example لكي يعمل الأمر السابق، يجب على المسار test أن يكون موجودًا بالفعل. لإخبار mkdir بأنّه يجب عليه إنشاء أيّ مساراتٍ ضرورية في طريقه إلى إنشاء مسارٍ مطلوب، يمكنك استخدام الخيار -p معه. يسمحُ لك هذا بإنشاء مساراتٍ ومجلّدات متداخلة في خطوةٍ واحدة. يمكننا إنشاء هيكلة مجلّدات تبدو مثل some/other/directories عبر كتابة: mkdir -p some/other/directories سيقوم الأمر السابق بإنشاء مجلّد some أولًا، ثمّ other ثانيًا بداخله، وأخيرًا مجلّد directories بداخل هذين المجلّدين. نقل وإعادة تسمية الملفّات والمجلّدات باستخدام mv يمكننا تحريكُ ملفٍ ما إلى مسارٍ جديد عبر استخدام الأمر mv. كمثال، يمكننا نقل الملف file1 إلى داخل المجلّد test عبر كتابة: mv file1 test لاستخدام هذا الأمر، سيجبُ علينا إعطاءه جميع العناصر التي نرغبُ بنقلها بالإضافة إلى المواقع التي نريدُ نقلها إليها في النهاية. يمكننا نقلُ ملفٍ ما إلى مجلّد المنزل الخاص بنا عبر استخدام حرف النقطة الخاص . الذي يشير إلى مسارنا الحالي (حرف النقطة يشير للمسار الحالي، ونحن الآن في مجلّد المنزل)، يجب علينا أن نتأكّد مما إذا كنّا في مجلّد المنزل بالفعل، ومن ثمّ ننفذ الأمر: cd mv test/file1 . قد يبدو هذا الأمر مبهمًا قليلًا، ولكن يمكننا استخدام الأمر mv أيضًا لإعادة تسمية الملفّات والمجلّدات. في الواقع، نقل وإعادة تسمية الملفّات ليسا سوى مجرّد عمليتين تضبطان الموقع والاسم لعنصرٍ موجودٍ حالي. لذا، لإعادة تسمية الملفّ test إلى testing ، يمكننا كتابة: mv test testing ملاحظة: من المهمّ أن تُدركَ أنّ نظام لينكس لن يمنعك من القيام بإجراءاتٍ تدميرية له. إذا قمتَ بمحاولة إعادة تسمية ملفٍ ما واخترت اسمًا يوجد بالفعل لملفٍ آخر بنفس المسار، فحينها فإنّه سيتم الكتابة فوق الملفّ القديم والإبقاء على الملفّ الجديد الذي تقوم بنقله. لا يوجد هناك أيّ طريقة لاسترجاع الملفّ القديم في حال قمتَ بالكتابة فوقه. نسخ الملفّات والمجلّدات باستخدام cp مع الأمر mv، يمكننا نقل أو إعادة تسمية ملفٍّ ما أو مجلّد، ولكن لا يمكننا استنساخه. يُمكن للأمر cp أن يقوم بعملِ نسخةٍ جديدة من عنصرٍ موجودٍ حاليًا. كمثال، يمكننا نسخ الملف file3 إلى ملفٍ جديد يُدعى file4: cp file3 file4 على عكس العملية التي يقوم بها mv والتي بعدها لن يبقى ملفّ file3 موجودًا، فإنّنا الآن نمتلكُ كلًّا من الملفّين file3 و file4. ملاحظة: كما هو الحال مع الأمر mv، فإنّه يُمكن أيضًا أن يتم الكتابة فوق ملفٍ ما إذا لم تكن حذرًا حول اسم الملفّ الذي ستستخدمه كهدفٍ للعمليّة. كمثال، إذا كان الملفّ file4 موجودًا بالفعل بالمثال أعلاه، فإنّه سيتم استبدال محتوياته بشكلٍ كامل بمحتويات الملفّ file3. بهدفِ نسخ المجلّدات والمسارات، يجب أن تستخدم الخيار -r مع الأمر cp. هذا الخيار هو اختصار لكلمة "recursive”، حيثُ أنّه يقوم بنسخ المجلّد بالإضافة إلى جميع محتوياته الداخلية. من الضروري استخدام هذا الخيار عند نسخ المجلّدات، بغضّ النظر عمّا إذا كان المجلّد فارغًا أم لا. كمثال، انسخ المجلّد some إلى مجلّدٍ جديد يدعى again ، عن طريق الأمر: cp -r some again على عكس الملفّات، والتي يُمكن الكتابة فوقها في حال كانت موجودة بالفعل، فإنّه في حال كان المجلّد الهدف موجودًا بالفعل، فإنّه سيتم نسخ المجلّد أو الملفّ إلى داخل المجلّد الموجود حاليًا: cp file1 again هذا الأمر سيقوم بإنشاء نسخةٍ جديدة من ملفّ file1 ويضعها داخل مجلّد again. حذف الملفّات والمجلّدات باستخدام rm و rmdir يمكنك استخدام الأمر rm لحذف ملفٍ معيّن. ملاحظة: كنّ حذرًا بشدّة عند استخدام أوامر تدميرية مثل rm . لأنّه لا يوجد هناك أمرٌ استرجاعي لهذه الأفعال في حال حصلت، لذلك فمن الممكن أن تقومَ بتدميرِ ملفاتٍ مهمّة بالخطأ للأبد. لحذف ملفٍ عادي، طبّق: cd rm file4 بالمثلِ أيضًا، لحذف المجلّدات الفارغة، يمكننا استخدام الأمر rmdir. سينجحُ هذا الأمر فقط في حال كان المجلّد فارغًا. كمثال، لحذف مجلّد example الموجود بداخل مجلّد testing، يمكننا أن نكتب: rmdir testing/example إذا كنتَ ترغبُ في حذف مجلّد غير فارغ، فسيجبُ عليك استخدام الخيار -r مع الأمر rmdir، والذي سيقوم بحذف جميع محتويات مسارٍ معيّن مباشرةً، بالإضافة إلى المجلّد نفسه. كمثال، لحذف مجلّد again وكل شيءٍ بداخله، يمكننا أن نكتب: rm -r again مُجدّدًا، تجدرُ الإشارة إلى أن هذه العمليات دائمة. كنّ متأكدًا دائمًا أنّ الأمر الذي كتبته هو أمرٌ ترغبُ في تنفيذه حقًا. تحرير الملفّات حاليًا، صرنا نعرف كيفية التّعامل مع الملفّات ككائنات، ولكننا لم نتعلّم بعد كيفية تحريرها بشكلٍ فعلي وكيفية إضافة المحتوى إليها. الأمر nano هو واحدٌ من أبسط محررات النصوص المُستعملة عبر سطر الأوامر في نظام لينكس، وهو نقطة بدايةٍ عظيمة للمبتدئين. يقوم nano بتنفيذ الأوامر بشكلٍ شبيه ببرنامج less الذي تحدّثنا عنه من قبل، ولكنّه يحتلّ شاشة الطرفيّة بأكملها طوال فترة استخدامه. يُمكن للمحرر nano أن يقوم بفتح ملفاتٍ موجودة أو إنشاء أخرى. إذا قررتَ إنشاء ملفٍ جديد، يمكنك تمرير اسمه للمحرر nano الآن أو لاحقًا عندما تودُّ حفظ المحتوى الذي تريده. يمكننا فتح الملفّ file1 للتحرير عبر كتابة: cd nano file1 سيقوم برنامج nano بفتح الملفّ (والذي هو فارغٌ حاليًا). ستبدو الواجهة شيئًا كالتالي: GNU nano 2.2.6 File: file1 [ Read 0 lines ] ^G Get Help ^O WriteOut ^R Read File ^Y Prev Page ^K Cut Text ^C Cur Pos ^X Exit ^J Justify ^W Where Is ^V Next Page ^U UnCut Text ^T To Spell بالأعلى، لدينا اسم التطبيق واسم الملفّ الذي نقوم حاليًا بتحريره. في المنتصف، محتوى الملفّ الفارغ حاليًا. في الأسفل، يظهرُ عددٌا من المفاتيح التي يُمكن أن يتم ضغطها مع بعضها البعض لتنفيذ مهامٍ معيّنة للتحكم في المحرّر. لكلّ واحدٍ من هؤلاء، يعني الحرف ^ مفتاحَ CTRL. للحصول على المساعدة من المحرّر، اضغط على مفاتحي: Ctrl + G عندما تنتهي من تصفّح المساعدة، اضغط على Ctrl + X للرجوع إلى مستندك. قم بكتابة / تعديل أيِّ نصٍ تريده. في هذا المثال، سنكتبُ العبارتين التاليتين فقط: Hello there. Here Is some text. لحفظ ما كتبناه، يمكننا أن نضغط: Ctrl + O هذا هو الحرف O وليس الرقم صفر. سيسألك البرنامج عن تأكيد اسم الملفّ الذي تودّ حفظه: File Name to Write: file1 ^G Get Help M-D DOS Format M-A Append M-B Backup File ^C Cancel M-M Mac Format M-P Prepend كما ترى، تغيّرت الخيارات التي بالأسفل أيضًا. تعتمد هذه الخيارات على السياق، بمعنى أنّها ستتغير طبقًا لِمَا تحاولُ أن تفعله. إذا كان الملفّ file1 لا يزالُ ملفًا ترغبُ بالكتابة إليه، اضغط على مفتاح "Enter”. إذا قمنا بعمل بعض التغييرات الإضافية ورغبنا في حفظ الملفّ والخروج من البرنامج، فسنتمكّن من رؤية موجّه أوامرٍ مشابه. قم بإضافة سطرٍ جديد، ثمَّ حاول الخروج من البرنامج عبر كتابة: Ctrl + X إذا لم تقم بحفظ المحتويات قبل الخروج بعد عمل تغييراتك، فسيتم سؤالك عمّا إذا كنتَ تريد حفظها أم لا: Save modified buffer (ANSWERING "No" WILL DESTROY CHANGES) ? Y Yes N No ^C Cancel يمكنك كتابة "Y” لحفظ التغييرات، "N” لرفضها والخروج، أو "Ctrl + C” لإلغاء عمليّة الخروج من البرنامج والعودة إليه. إذا اخترتَ الحفظ، فستحصلُ على نفسِ موجّه أوامر الملفّ الذي حصلتَ عليه من قبل، لتأكيد ما إذا كنتَ تريد حفظ التغييرات إلى نفس الملفّ. اضغط زرّ Enter لحفظ الملفّ والخروج من المحرّر. يمكنك رؤية محتويات الملفّ الذي أنشأته إمّا عبر برنامج cat لعرض محتوياته، أو برنامج less لعرضِه للقراءة. بعد عرضِ البرنامج باستخدام less ، تذكّر أنّه يجب عليك الضغط على زرّ q للرجوع للطرفيّة. less file1 Hello there. Here is some text. Another line. محرّرٌ آخر يمكنُ أن يتم توجيهكَ إليّه في شروحاتٍ مستقبلية هو vim أو vi . هذا المحرّر أكثر تطورًا وأكثر قوةً ، ولكنّ يتطلب الكثير لتعلّمه. إذا أخبركَ أحدهم باستخدام vim أو vi، فاستخدم nano عوضًا عن ذلك. إذا كنتَ ترغبُ بتعلّم المزيد حول كيفية استخدام vim ، فاقرأ هذا الدّرس حول كيفية البدء مع vim. دورة علوم الحاسوب دورة تدريبية متكاملة تضعك على بوابة الاحتراف في تعلم أساسيات البرمجة وعلوم الحاسوب اشترك الآن الخاتمة الآن، يجب أن تكونَ قد امتلكتَ أساسيات فهم كيفية التنقّل في خادومك العامل بنظام لينكس وكيفية عرض الملفّات والمسارات المتوّفرة. يجبُ أن تكون قادرًا أيضًا على معرفة أساسيات أوامر التعامل مع الملفّات والتي ستسمح لك بعرض، نسخ، نقل أو حذف الملفّات. أخيرًا، يجب أن تكون مرتاحًا مع بعض أساسيات تحرير الملفّات باستخدام محرّر nano. مع هذه المهارات القليلة، يجب أن يكون قادرًا على متابعة مشوارك في شروحاتٍ أخرى وتعلّم كيفية استخراج أكبر إمكانية متوفّرة من خادومك. في الدّرس التالي، سنناقش كيفية عرض وفهم الأذونات في لينكس. ترجمة -وبتصرّف- للمقال: Basic Linux Navigation and File Management.
×
×
  • أضف...