المحتوى عن 'تطبيق'.



مزيد من الخيارات

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

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

نوع المُحتوى


التصنيفات

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

التصنيفات

  • PHP
    • Laravel
    • ووردبريس
  • جافاسكريبت
    • Node.js
    • jQuery
    • AngularJS
    • Cordova
  • HTML5
  • CSS
    • Sass
    • إطار عمل Bootstrap
  • SQL
  • سي شارب #C
    • منصة Xamarin
  • بايثون
    • Flask
    • Django
  • لغة روبي
    • إطار العمل Ruby on Rails
  • لغة Go
  • لغة جافا
  • لغة Kotlin
  • برمجة أندرويد
  • لغة Swift
  • لغة R
  • لغة TypeScript
  • سير العمل
    • Git
  • صناعة الألعاب
    • Unity3D
  • مقالات برمجة عامة

التصنيفات

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

التصنيفات

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

التصنيفات

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

التصنيفات

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

التصنيفات

  • الإنتاجية وسير العمل
    • مايكروسوفت أوفيس
    • ليبر أوفيس
    • جوجل درايف
    • شيربوينت
    • Evernote
    • Trello
  • تطبيقات الويب
    • ووردبريس
    • ماجنتو
  • أندرويد
  • iOS
  • macOS
  • ويندوز

التصنيفات

  • شهادات سيسكو
    • CCNA
  • شهادات مايكروسوفت
  • شهادات Amazon Web Services
  • شهادات ريدهات
    • RHCSA
  • شهادات CompTIA
  • مقالات عامة

أسئلة وأجوبة

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

التصنيفات

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

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

  1. إذا كنت جديدًا في العمل المستقل، فإن التعامل مع فواتير العملاء سيكون من الأمور المرعبة (والمُمِلّة) التي سوف تتعرض لها. تجعل الفواتيرُ عملَك يبدو احترافيًّا، لكن من الصعب تخمين محتوًى جيدٍ لها، أو معرفة الطريقة المناسبة لإرسالها للعميل. من حسن الحظ، فإن لديك العشرات من أدوات الفواتير الممتازة- والتي تقوم بالعمل الصعب نيابةً عنك- ويمكنك الاختيار من بينها. ما عليك فقط إلا أن تُدخل بعض بيانات العميل، ثم تحلل البيانات المطلوبة في كل فاتورة، وسيقوم التطبيق بإنجاز كل شيء نيابةً عنك، وهذا يشمل إرسال التذكيرات، وتتبع الأرباح، وغيرها الكثير. في هذه المقالة سوف تتعلم كيف يمكن لتطبيقات الفواتير أن تحسن من سير حياتك كمستقل. ثم سأقدم لك أفضل التطبيقات للفواتير الخاصة بالكُتّاب المستقلين. هيا لنبدأ! لماذا عليك استخدام تطبيق فواتير الفواتير التي تبدو احترافية في شكلها وصيغتها تعطي انطباعًا لعملائك أنك جادٌّ في عملك. وبالنسبة لك كمستقل، فالفواتير مهمة مستمرة وضرورية طوال حياتك المهنية. ففي كل مرة تنتهي من مرحلة معينة من مراحل مشروع ما، أو تنتهي من مشروع كامل، فسوف ترسل لعميلك فاتورة. هذا يضمن أن لدى كلٍّ منكما مستندًا يوضح سير العمليات المالية ذهابًا وإيابًا. يعتبر إنشاء ومتابعة الفواتير أمرًا مُمِلًّا بصراحة، لأنها تتطلب منك أن تكون دقيقًا في وصف العمل وتوثيقه. وكلما زاد عدد العملاء، كلما زادت الفواتير، لهذا أنصحك أن تستخدم تطبيقًا للفواتير ليهتم بمعظم أعمالك. في هذه الأيام، تقوم تطبيقات الفواتير بعمل أكثر من مجرد أنها تجعل شكل الإيصالات المالية منسقًا وجميلًا. تتيح لك معظم التطبيقات أن تُرسل تذكيرات للعملاء، وإضافة الرسوم المتأخرة، وتتبع أرباحك، والكثير. بمعنى آخر، هذه التطبيقات توفر على المستقلين الكثير من الوقت والجهد. وأفضل بديل لهذه التطبيقات هو أن تقوم بتوظيف محاسب، لكن هذا الخَيَار مكلف جدًّا. أفضل 3 تطبيقات للفواتير تخص الكُتّاب المستقلين التطبيقات التالية ليست للمستقلين فحسب، بل يمكن لكل من يدير عملًا حرًا أن يستفيد منها. تجدر الإشارة إلى أن أفضل الخدمات تكون مدفوعةً، لذا من الممكن أن تكون هناك تكلفةٌ شهرية بسيطة، غير أن هذا هو الوقت الذي سوف تزيد فيه أرباحك مع زيادة العملاء، ولا تجعل هذه التكلفة الشهرية البسيطة تُثنيك عن الحل الصحيح. 1. تطبيق Freshbooks Freshbooks هو واحد من ألمع الأسماء في تطبيقات الفواتير. فقد صار شعبيًّا بفضل مجموعة واسعة من المميزات، وواجهة المستخدم الممتازة، ولا يُخيّب من يستخدمه. قبل هذا التطبيق، كنت أستخدم فقط فواتير PayPal. والانتقال لهذا التطبيق كان بمثابة تجديدٍ للهواء بالنسبة لي. فيه الكثير من المميزات، ولا زلت أكتشف الجديد فيه بمرور الوقت، على سبيل المثال، يُتيح لك التطبيق أن تفرض رسومًا على العملاء باستخدام بطاقةِ الائتمان، وإرسالَ تذكيراتٍ للفواتير المتأخرة، وترجُمَتِهِم، والعديد من المميزات الأخرى. وأنت كمستقلٍ، سوف تُقَدِّرُ فكرة أن تكون قادرًا على فرض رسوم للدفع المسبق، بدلًا من إنشاء فاتورة مستقلة لكل مرحلة من مراحل المشروع. من ينبغي عليه استخدام تطبيق Freshbooks عادةً ما أكون حذرًا من توصية حلٍّ واحد لكل الأفراد، لكن يمكنني استثناء Freshbooks من ذلك. فلديه ما يكفي من المميزات التي يمكنك تصورها لإدارة عمل تقليديّ، وهو رائع جدًّا بالنسبة للمستقلين. مشكلته الوحيدة هي أنه لا يقبل الدفع عن طريق PayPal، وإذا كان عملائك يُصرون على الدفع عن طريق PayPal، فإن عليك التوجه إلى حلٍّ آخر. السعر خطة Freshbook الأولية (starter plan) سوف تُكلِّفُك 15$ في الشهر، وتدعم التعامل مع 5 عملاء في نفس الوقت. وإذا اتسعت قاعدة عملائك فيمكنك أن تُرقّي نظامك إلى الخطة الإضافية (Plus Plan)، التي سوف تكلفك 10$ إضافية فقط، وتدعم التعامل حتى 50 عميلًا. 2. تطبيق Wave يمتلك Wave مميزات منافسة لتطبيق Freshbooks، فهو يمنحك القدرة على إنشاء فاتورة احترافية الشكل باستخدام القوالب، مع إمكانية تَكيِيفِ هذه القوالب مع شعارِك في دقائق. علاوة على ذلك يمكنك أن تباشر الدفع عن طريق البنك وبطاقات الائتمان، والبقاء في أول قائمة الفواتير غير المدفوعة، والكثير من المميزات الأخرى. والأمر الذي يُميز تطبيق Wave حقًّا، هي التكاليف الخاصة بفريق العمل، فإذا كنت تبحث عن تنمية عملك المستقل وتكوين فريق عمل، فبإمكان تطبيق Wave أن يساعدك على إدارة الرواتب، بالإضافة إلى أنه مجانيّ، فلا يلزمك أن تُوَسِّعَ ميزانيتِك المالية لاستيعاب نفقات جديدة. من ينبغي عليه استخدام تطبيق Wave إن خبرتي في استخدام تطبيق Wave محدودة، لكنها متينة. فقد قدَّمت بعض الفواتير، وفي كل مرة حصلت على الدفع دون وجود عقبات. أنه من أفضل التطبيقات في الأنحاء فيما يخص ميزةَ دفع الرواتب، مما يجعله مناسبًا لك إن كنت تحب العمل ضمن فريق، أو توظيف مصادر خارجية. السعر: يُعدُّ تطبيقَ Wave خدمةً مجانيةً، فهو مثل PayPal في أنه يفرض رسومًا قدرها 2.9% على تحويلات بطاقات الائتمان، إضافة إلى 0.03% رسومَ خدمة. هذا التطبيق يدعم الدفع عن طريق البنك أيضًا، برسوم قدرها 1%. 3. PayPal Invoices إذا كنت كاتبًا مستقلًا، فأنت بالتأكيد قد استخدمت PayPal في إحدى مراحل مسيرتك المهنية. أغلب العملاء الذين أتعامل معهم يستخدمونه كطريقةٍ من طرق الدفع، إذ يمكنك به أن تشتري- تقريبًا- أي شيء على الإنترنت. من المهم ملاحظة أن PayPal ليس تطبيقًا للفواتير في حد ذاته، بل هو خدمة لتحويل الأموال، مع بعض مميزات الفواتير المتواضعة المدمجة بداخله. فمميزات الفواتير الخاصة به ليست قريبة أبدًا من المستوى الجيد الذي يتمتع به كلا من Freshbook وWave. ورغم ذلك، فهذه المنصة لا تزال تستحق أن توضع في القائمة، لأنها شعبية جدًا. بالإضافة إلى ذلك، فإذا كان لديك بالفعل حساب على PayPal، فأنت لن تحتاج إلى التسجيل في أية خدمات جديدة. من ينبغي عليه استخدام PayPal. العديد من المستقلين لا يحبون الاعتماد على PayPal كليًّا فيما يخص أجورهم ورواتبهم. لذلك، يمكنك أن تستقبل راتبك عبر PayPal من العملاء الذين يفضلون استخدامه، والتعامل مع باقي العملاء باستخدام تطبيق مختلف. باختصار، لا تقُم بالحد من إمكانية دخلك ورواتبك. تعوّد على PayPal، وتعلم كيف ترسل الفواتير من خلاله، حتى تتسع قاعدة عملائك. السعر: يمكن لأيٍّ كانَ أن يُنشأ حسابًا مجانيًّا على PayPal، لكنهم يفرضون رسومًا على كل دفع تحصل عليه. هذا يختلف من شخص لآخر، اعتمادًا على بلدك، ومصدر المال، ويمكن للأمر أن يكون مكلفًا وحادًّا في بعض الأحيان. ختامًا تطبيقات الفواتير الحديثة تقوم بتسهيل وتبسيط عمل حياتك، فكلما وفرتَ وقتَك، وأرحتَ نفسك من مطارة العملاء لأجل دفع الفواتير، كلما كَرَّست نفسك للعمل، وأقدمت على أعمال جديدة. إذا كان عملك لا يزال وليدًا، فأنت تحتاج إلى بعض العملاء قبل أن تبدأ في القلق بشأن الفواتير. إحدى المنصات التي يمكنك أن تجد عليها عملاء بالنسبة لك ككاتب مستقل- هو موقع خمسات ومستقل، لذا أنصحك أن تستكشفه. مجرد ما إن تحصل على بعض العمل لحسابك الخاص، حينها عليك أن تختار تطبيقًا للفواتير ليهتم بأمرهم. إليك أفضل ثلاثة تطبيقات بالنسبة لي: تطبيق Freshbooks : تطبيقُ فواتيرٍ رائعٌ، يحتوي على كل المميزات لأي عمل. تطبيق Wave : إذا كنت تعمل مع مستقلين آخرين، فهذه أفضل خدمة لك. PayPal Invoices : يتيح لك موقع PayPal أن ترسل الفواتير، بالإضافة إلى كونه خدمةَ الدفعِ الإلكترونية الأكثر شعبية. برأيك ما هو أفضل تطبيق للفواتير بالنسبة للكُتّاب المستقلين؟ أخبرنا عن سبب ذلك في التعليقات في الأسفل! ترجمة- وبتصرف- للمقال 3 Best Invoicing Apps for Freelance Writers لصاحبه ALEXANDER CORDOVA حقوق الصورة البارزة محفوظة لـ Freepik
  2. تُظهر هذ الإرشادات كيفية إنشاء تطبيقات JS/HTML Cordova ونشرها على منصّات موبايل أصليّة متنوعة باستخدام واجهة سطر أوامر كوردوفا (cordova (CLI, راجع CLI reference لتفاصيل مرجعية عن واجهة سطر أوامر Cordova. تثبيت Cordova CLI واجهة سطر أوامر Cordova موزّعة كحزمة npm (نظام إدارة حزم). اتبع الخطوات التالية لتثبيت أداة cordova CLI : 1- حمّل وثبّت Node.js. خلال التثبيت يجب أن تكون قادراً على استدعاء node و npm على سطر الأوامر الخاص بك. 2- (اختياري) حمّل وثبّت git client, إذا لم يكن لديك نسخة مسبقًا. قم بتثبيتها, وبعدها يجب أن تكون قادرًا على استدعاء git على سطر الأوامر الخاص بك. حيث يستخدمها CLI لتحميل الموارد عندما يتم الاشارة إليها باستخدام git repo 3- ثبّت cordova باستخدام أداة npm لـ Node.js. حيث سيُحمّل cordova أوتوماتيكيًا باستخدام أداة npm . في OS ولينكس $ sudo npm install -g cordova في أنظمة OSX و LINUX قد يكون الحاق الأمر npm بـ sudo ضروريًا لتثبيت أداة التطوير هذه في الأدلة المقيّدة مثل /usr/local/share إذا كنت تستخدم الأداة الاختيارية nvm/nave أو تمتلك صلاحية الوصول الى دليل التثبيت. يمكنك الاستغناء عن البادئة sudo . في نظام التشغيل ويندوز Windows C:\>npm install -g cordova تخبر العلامة g- الأمر npm بتثبيت cordova بشكل عام. وإذا لم يتم التحديد سيتم التثبيت في الدليل الفرعي node_modules من مسار التثبيت الحالي. بعد إتمام التثبيت يجب أن تتمكن من تشغيل cordova من موجه الأوامر بدون معامِلات، ويجب أن تقوم Cordova بطباعة نص للمساعدة على شاشة موجه الأوامر.. إنشاء التطبيق اذهب الى الدليل الذي تدير فيه شفرتك المصدرية. وأنشئ مشروع Cordova $ cordova create hello com.example.hello HelloWorld هذا ينشئ بنية الدليل المطلوب لتطبيق cordova الخاص بك. افتراضيًا, سكريب cordova create يولد هيكلية تطبيق معتمد على الوب والذي صفحته الرئيسية هي ملف المشروع www/index.html. إضافة منصّات يجب تشغيل جميع الأوامر اللاحقة ضمن الدليل الرئيسي المشروع، أو أي دليل فرعي: $ cd hello أضف المنصّات التي ترد لتطبيقك أن يستهدفها. سنضيف منصّة أندرويد و IOS والتأكد من حفظها الى config.xml و package.json: $ cordova platform add ios $ cordova platform add android للتأكد من مجموعتك الحاليّة للمنصّات: $ cordova platform ls تشغيل أوامر لإضافة أو إزالة المنصّات يؤثّر على محتويات دليل منصّات المشروع، حيث تظهر كل منصّة محدّدة كدليل فرعي. ثبيت المتطلبات المسبقة للبناء لإنشاء التطبيقات وتشغيلها، يلزمك تثبيت حزم SDK لكل منصّة تريد استهدافها. بدلاً من ذلك، إذا كنت تستخدم متصفح للتطوير فيمكنك استخدام منصّة browser التي لا تتطلب أية SDKs للمنصّة. للتحقق مما إذا كنت مستوفيًا لمتطلبات إنشاء المنصّة: $ cordova requirements Requirements check results for android: Java JDK: installed . Android SDK: installed Android target: installed android-19,android-21,android-22,android-23,Google Inc.:Google APIs:19,Google Inc.:Google APIs (x86 System Image):19,Google Inc.:Google APIs:23 Gradle: installed Requirements check results for ios: Apple OS X: not installed Cordova tooling for iOS requires Apple OS X Error: Some of requirements check failed بناء التطبيق افتراضيًا، Cordova تنشئ سكريبت يولد هيكلية تطبيق معتمد على الوب والذي صفحة البداية له هي ملف المشروع www/index.html. يجب تحديد أيّة تهيئة كجزء من معالج حدث deviceready المعرّف في www/js/index.js. قم بتشغيل الأمر التالي لبناء المشروع لجميع المنصّات: $ cordova build يمكنك اختياريًا تحديد المجال في كل بناء لمنصّات محدّدة- في هذه الحالة"ios" $ cordova build ios اختبار التطبيق غالباً ما تأتي حزم SDK لمنصّات الموبايل مع محاكي تشغّل صورة الجهاز, وبذلك يمكنك تشغيل التطبيق من الشاشة الرئيسية ومشاهدة كيفية تفاعله مع العديد من ميزات المنصّة. شغّل أمر مثل التالي لإعادة بناء التطبيق وعرضه ضمن محاكي منصّة معيّنة: $ cordova emulate android تبعاً لأوامر محاكي Cordova تحدّث (refreshes) صورة المحاكي لعرض أحدث تطبيق, والذي قد أصبح متاحاً للوصول من الشاشة الرئيسية: في نفس الوقت يمكنك توصيل الهاتف إلى حاسوبك واختبار التطبيق مباشرةً: $ cordova run android قبل تشغيل هذا الأمر، تحتاج إلى إعداد الجهاز للاختبار، باتباع الإجراءات التي تختلف حسب كل منصّة. إضافة الإضافات Plugins يمكنك تعديل التطبيق المولَّد افتراضياً للاستفادة من ميزات تقنيات الوب المعيارية, ولكن ستكون بحاجة لإضافة Plugins لكي يتمكّن التطبيق من الوصول لميزات على مستوى الجهاز. تعرض الإضافة واجهة برمجة تطبيقات جافا سكربت Javascript API لوظيفة SDK الأصلية. يتم استضافة الإضافات عادةً على npm ويمكنك البحث عنهم في صفحة plugin search. تُزوَّد بعض مفاتيح API من قبل مشروع المصدر المفتوح Apache Cordova ويشار إليها باسم Core Plugin APIs $ cordova plugin search camera لإضافة وحفظ إضافة الكاميرا إلى config.xml و package.json، سنحدّد اسم حزمة لإضافة الكاميرا: $ cordova plugin add cordova-plugin-camera Fetching plugin "cordova-plugin-camera@~2.1.0" via npm Installing "cordova-plugin-camera" for android Installing "cordova-plugin-camera" for ios يمكن أن تضاف الإضافات أيضاً باستخدام الدليل أو باستخدام git repo استخدم plugin ls أو plugin list أو plugin لوحدها لعرض الإضافات المثبّتة حالياً. كلٌ يُعرض من خلال معرّفه الخاص: $ cordova plugin ls cordova-plugin-camera 2.1.0 "Camera" cordova-plugin-whitelist 1.2.1 "Whitelist" استخدام mergesلتخصيص كل منصّة في حين أن Cordova تسمح لك بنشر التطبيق بسهولة على منصّات مختلفة, إلا أنه في بعض الأحيان ستحتاج لإضافة تخصيصات. في هذه الحالة, لن تقوم بتعديل الملفات المصدرية في أدّلة www المتعددة ضمن دليل المستوى العالي platforms , لأنه يتم استبداله بشكل منتظم مع مصدر المنصّات المتعددة لدليل المستوى العالي www بدلاً من ذلك، دليل المستوى الأعلى merges يوفر مكاناً لتحديد الموارد للنشر على منصّات محدّدة. يعكس كل دليل فرعي خاص بالمنصّة ضمن عمليات merges بنية الدليل لشجرة المصدر www، مما يسمح لك بتجاوز أو إضافة ملفات حسب الحاجة. على سبيل المثال، إليك كيفية استخدام عمليات merges لزيادة حجم الخط الافتراضي لأجهزة أندرويد: حرّر ملف www/index.html , مضيفاُ رابط ملف CSS إضافي, overrides.css في هذه الحالة: <link rel="stylesheet" type="text/css" href="css/overrides.css" /> يمكن اختياريا إنشاء ملف www/css/overrides.css فارغ. والذي سيطبق من أجل كل بناء غير مخصص للأندرويد, لمنع خطأ الملف مفقود (missing-file) أنشئ ملف css على دليل فرعي ضمن merges/android, ثم أضف ملف overrides.css المقابل. حدّد CSS الذي يتجاوز حجم الخط الافتراضي 12-نقطة داخل www/css/index.css, على سبيل المثال: body { font-size:14px; } عندما تعيد بناء المشروع, تضمّن نسخة الأندرويد حجم الخط المخصص, بينما تظل البقية دون تغيير. كما يمكن استخدام merges لإضافة ملفات غير موجودة في الدليل الأصلي www. على سبيل المثال, تطبيق يمكنه تضمين back button رسومي داخل واجهة الـ iOS, مخزّن في merges/ios/img/back_button.png , ، في حين أنه يمكن لنسخة الأندرويد بدلاً من ذلك التقاط الأحداث backbutton من زر الأجهزة المقابلة. تحديث كوردوفا وتطبيقك بعد تثبيت أداة Cordova, يمكنك دوماً تحديثها إلى آخر إصدار من خلال تشغيل الأمر $ sudo npm update -g cordova استخدم هذه الصّياغة لتثبيت إصدار محدّد: $ sudo npm install -g cordova@3.1.0-0.2.0 نفّذ cordova -v لمعرفة النسخة الحالية قيد التشغيل. شغّل الأمر التالي لإيجاد آخر نسخة تم إصدارها Cordova: $ npm info cordova version لتحديث المنصّة التي تستهدفها: $ cordova platform update android --save $ cordova platform update ios --save ...etc. ترجمة -وبتصرّف- للمقال Create your first Cordova app للمساهمين في كتابة المقال على GitHub هذا المقال منشور تحت الرخصة Apache License, Version 2.0
  3. تساعدك الواجهة البرمجية (API) الخاصة بموقع التواصل الاجتماعي تويتر في إدارة الحسابات الموجودة فيه، كما وتسمح لك بالتنقيب عما يحتويه من بيانات. هذا الأمر يفيدك – مثلاً - في عملية ترويج هوية المؤسسة أو المنظمة التي تعمل فيها، وكذلك يُعدّ ممتعًا ومسليًا للمستخدمين الأفراد وهواة البرمجة. في هذا الدرس سوف نشرح لكم الخطوات اللازمة لإنشاء تطبيق توتير، وبعد ذلك سنبني سكربت بايثون من خلال استخدام مكتبة Tweepy للاستفادة من التطبيق و نشر تغريدات من خلاله. المتطلبات قبل البدء، تأكد من وجود المتطلبات التالية: وجود حساب توتير مرتبط برقم هاتف محمول صحيح، وتستطيع إعداد ذلك بالذهاب إلى خيار الهاتف المحمول في قائمة الإعدادات والخصوصية. وجود بيئة بايثون مثبتة على جهاز العمل. الخطوة الأولى: إنشاء تطبيق تويتر لنبدأ في بناء تطبيق تويتر والحصول على مفاتيح ورموز الوصول الخاصة بالواجهة البرمجية للتطبيق. هذه الرموز هي التي تسمح لك بالاستيثاق من أي تطبيق تطوّره لكي يعمل مع تويتر. كما ذكرنا في المتطلبات، فأنت تحتاج لرقم هاتف محمول لكي تستطيع بناء التطبيق. افتح المتصفح وزر هذا الرابط وسجّل الدخول للصفحة باستخدام بيانات حسابك. اضغط بمجرد ولوجك على الزر المعنون ب (Create New App). سوف تُوجَّه إلى صفحة بناء التطبيق التالية: أدخل في هذه الصفحة الحقول المطلوبة كما في المثال التالي: الاسم: AcademyHsoubTest الوصف: Academy Hsoub Application الموقع: https://my.example.placeholder اقرأ اتفاقية مطور تويتر. إذا كنت موافقاً عليها، اضغطعلى خيار الموافقة واضغط على الزر المعنون ب Create your Twitter application والموجود في أسفل الصفحة، وسوف تتلقى صفحة تأكيد على ذلك. ستُوجَّه بعد أن نجاح إنشاء التطبيق إلى صفحة التطبيق التالية، والتي تُقدم لك بعض المعلومات العامة عن التطبيق. الخطوة الثانية: تعديل مستوى الإذن للتطبيق وتوليد رموز الوصول الخاصة به من صفحة التفاصيل (Details Page) السابقة، اذهب لخيار الأذونات (Permissions) وذلك للتأكد من أننا نمتلك مستوى الوصول المطلوب لتوليد مفاتيح التطبيق. يمتلك التطبيق تلقائيا أذونات القراءة والكتابة. إذا لم يكن كذلك، عدّل التطبيق وتأكد من أن خيار القراءة والكتابة هو المحدد من قائمة الأذونات. هذا الأمر يسمح للتطبيق بالنشر على حساب تويتر بالنيابة عنك. اذهب بعد التأكد من أذونات التطبيق التي تسمح له بالنشر إلى خيار المفاتيح ورموز الوصول (Keys and Access Tokens). ستُنقَل إلى صفحة تعرض لك مفتاح المستهلك (Consumer Key) والرمز السري للمستهلك (Consumer Secret)، وكذلك تُمكنك من توليد رمز الوصول ورمز الوصول السري. هذه الرموز والمفاتيح هي التي ستقوم بعملية الاستيثاق لتطبيقك مع تويتر. اضغط على الزر المعنون ب (Create my access token) لتوليد رمز الوصول ورمز الوصول السري. أصبح لديك الآن رمز الوصول ورمز الوصول السري. الخطوة الثالثة: تثبيت مكتبة Tweepy تستطيع أن تستخدم مجموعة متنوعة من لغات البرمجة للتخاطب مع الواجهة البرمجية لتويتر. سنختبر التطبيق الذي أنشأناه عن طريق تشغيل سكربت بايثون ينشُر نصًّا معيّنًا على حساب تويترللمستخدم. مكتبة Tweepy مفتوحة المصدر وسهلة الاستخدام وتسمح للمشاريع المكتوبة بلغة البايثون بالوصول للواجهة البرمجية لتويتر بكل سهولة. سنستخدم أداة pip لتثبيت مكتبة tweepy. أنشئ مجلدًا خاصًّا للمشروع باسم twitter. تأكد قبل تثبيت المكتبة أن أداة pip مُحدثة: >> pip install --upgrade pip بعد أن تُحدَّث الأداة بنجاح، نثبّت مكتبة Tweepy: >> pip install tweepy بعد تثبيت المكتبة تستطيع البدء بكتابة البرنامج. الخطوة الرابعة: بناء البرنامج الذي يتخاطب مع الواجهة البرمجية لتويتر أصبحنا، بعد أن بنينا التطبيق وولّدنا الرموز والمفاتيح اللازمة للوصول للتطبيق، على مشارف بناء البرنامج الذي سينشر بالنيابة عنك. أنشئ باستخدام محرر النصوص المفضل لديك ملف بايثون باسم helloworld.py في داخل المجلد twitter الذي أنشأناه في الخطوة السابقة. في بداية الملف، نحتاج أن نستورد المكتبة باستخدام جملة import: import tweepy سننشئ متغيرات لكل مفتاح ورمز ولّدناه. استبدل ما بين علامات التنصيص في المتغيرات التالية بالمفاتيح والرموز التي تم توليدها في تطبيقك الخاص. import tweepy consumer_key = 'your_consumer_key' consumer_secret = 'your_consumer_secret' access_token = 'your_access_token' access_token_secret = 'your_access_token_secret' ننشئ بعدها عنصرًا من الصنف OAuthHandler الموجود في مكتبة Tweepy وسنمرر لهذا العنصر المفاتيح والرموز الموجودة لدينا. يعمل هذا العنصر من خلال بروتوكول HTTP يعطي التصريح اللازم للأجهزة، الواجهات البرمجية، الخوادم والتطبيقات، ويعدّ هذا الصنف صنفا معياريا يقدّم ألية وصول آمن وذي تفويض كامل. نعدّ كذلك رموز الوصول وندمجها مع الواجهة البرمجية المنشأة من تعريف عنصر من نوع API. import tweepy consumer_key = 'your_consumer_key' consumer_secret = 'your_consumer_secret' access_token = 'your_access_token' access_token_secret = 'your_access_token_secret' auth = tweepy.OAuthHandler(consumer_key, consumer_secret) auth.set_access_token(access_token, access_token_secret) api = tweepy.API(auth) نحدّد في نهاية البرنامج النص الذي سننشره. عرف متغيرًا باسم tweet ومرر له النص الذي تريد نشره ومرّر هذا المتغير للدالة api.update_status. import tweepy # Create variables for each key, secret, token consumer_key = 'your_consumer_key' consumer_secret = 'your_consumer_secret' access_token = 'your_access_token' access_token_secret = 'your_access_token_secret' # Set up OAuth and integrate with API auth = tweepy.OAuthHandler(consumer_key, consumer_secret) auth.set_access_token(access_token, access_token_secret) api = tweepy.API(auth) # Write a tweet to push to our Twitter account tweet = 'أكاديمية حسوب، أهلا بالعالم' api.update_status(status=tweet) تستطيع الان حفظ الملف وتشغيله: >> python helloworld.py بعد انتهاء تنفيذ البرنامج، قم بمراجعة الحساب توتير الخاص بك. نشرت التغريدة على الخط الزمني لحسابك بنجاح وبذلك تكون قد هيّأت تطبيق تويتر واستخدمته من خلال مكتبة Tweepy! خاتمة باتباعك للشرح في هذا المقال، أنت أصبحت قادرا على تهيئة تطبيق تويتر وربطه بحسابك الخاص على الموقع. بمجرد بناء التطبيق وتوليد المفاتيح والرموز اللازمة، قمنا باستخدام التطبيق والرموز للاستيثاق من برنامج بايثون باستخدام المكتبة المفتوحة المصدر Tweepy. إذا لم تكن مبرمج بايثون، فإنه يوجد العديد من لغات البرمجة والمكتبات التي من الممكن استخدامها مع الواجهة البرمجية لتويتر. يحتوي الموقع الخاص بمطوري تويتر العديد من هذه المكتبات التي تدعم التخاطب مع الواجهة البرمجية لتويتر. ترجمة - بتصرّف - للمقال How To Create a Twitter App لصاحبته Lisa Tagliaferri. حقوق الصورة البارزة محفوظة لـ Freepik
  4. سنبدأ في هذا الدرس من سلسلة تعلّم برمجة تطبيقات أندرويد باستخدام Xamarin.Forms ببناء تطبيق عملي بمعايير تقنيّة عالية. حيث سنستخدم المعارف التي حصلنا عليها من الدروس السابقة في بناء تطبيق جهات اتصال بسيط لكنّه يستخدم تقنيّات ومفاهيم متقدّمة نسبيًّا. سنتناول هذا التطبيق على ثلاثة أجزاء متتالية، إليك وصف مختصر لمحتوى كلّ منها: الجزء الأوّل: شرح الغاية من التطبيق، وتوضيح فكرة نموذج المستودع Repository في بناء التطبيقات، مع بناء الهيكل العام للتطبيق، وهذا هو محتوى هذا الدرس. الجزء الثاني: تجهيز النواحي الوظيفيّة للمستودع وجعله قابلًا للاستخدام. الجزء الثالث: تنفيذ واجهتي التطبيق الرئيسية والفرعيّة الخاصّة بعرض التفاصيل. وتنفيذ عمليّة التنقّل بين الواجهتين الغاية من التطبيق وكيف يعمل فكرة التطبيق بسيطة للغاية، تتلخّص بعرض جهات اتصال موجودة مسبقًا وإمكانية البحث ضمنها، مع إمكانيّة إضافة جهات اتصال جديدة وتحريرها وحذفها. يعتمد التطبيق على وجود واجهتين. الواجهة الأولى هي الواجهة الرئيسيّة وتحتوي على قسم خاص بالبحث حسب الاسم أو الكنية عن أيّ جهة اتصال موجودة مسبقًا، بالإضافة إلى قائمة لعرض جهات الاتصال الناتجة عن عمليّة البحث، وأخيرًا زر خاص بإضافة جهات اتصال جديدة. انظر الشكل التالي الذي ينتج عند ضغط زر البحث FIND عند عدم تحديد أي معيار للبحث: عندما يقوم المستخدم بنقر زر البحث FIND دون أن يحدّد أي معيار، سيقوم التطبيق بعرض جميع جهات الاتصال الموجودة لديه، والتي ستكون في هذه النسخة من البرنامج عبارة عن بيانات وهمية موجودة ضمن ذاكرة التطبيق. أمّا عند تحديد المستخدم للاسم أو الكنيّة فسيعمل التطبيق على البحث مستخدمًا منطق AND. أمّا الواجهة الثانية، فتظهر عندما يلمس المستخدم إحدى جهات الاتصال من القائمة السابقة، حيث تعرض هذه الواجهة بيانات تفصيليّة حول جهة الاتصال هذه: الاسم والكنية ورقم الهاتف وعنوان البريد الإلكتروني والهوايات. انظر إلى الشكل التالي: من الممكن تعديل أيّ من هذه البيانات ثم ينقر المستخدم زر الحفظ لحفظها، أو أن ينقر زر الرجوع إلى الواجهة السابقة الموجود في الأعلى بجانب أيقونة البرنامج في حال لم يرغب بتعديل البيانات. كما يمكن للمستخدم أن يحذف جهة الاتصال هذه بنقره على زر الحذف Delete كما يظهر من الشكل السابق. وهذه ببساطة فكرة التطبيق. نموذج المستودع Repository عندما تكبر التطبيقات وتتنوّع المهام المطلوبة منها تبرز الحاجة لوسيلة لتنظيم العمل داخل التطبيق. في الحقيقة توجد العديد من النماذج التي تدعمها Xamarin لهذه الغاية مثل نموذج MVVM الذي يستخدم بفعالية ضمن Xamarin لتنظيم وفصل الأجزاء المسؤولة عن الواجهات عن الأجزاء المسؤولة عن منطق العمل عن تلك المسؤولة عن التعامل مع مزودات البيانات البعيدة أو المحلية باختلاف أنواعها. من النماذج التي أفضلها شخصيًّا هو نموذج المستودع Repository الذي أستخدمه على نحو واسع في جميع أنواع التطبيقات التي أعمل عليها. فهو أسلوب جميل ومنطقي ويسمح بتطوير التطبيق بشكل سلس وسريع للعمل في مختلف أنواع البيئات، وهو متوافق للعمل مع نموذج MVVM. يسمح نموذج المستودع بعزل الشيفرة البرمجيّة المسؤولة عن التعامل مع البيانات عن منطق البرنامج business logic. وفي هذا الأمر عدة فوائد من أهمّها: تنظيم البرنامج، وجعله أكثر قابليّة للفهم والتطوير. إجراء تطوير على أسلوب التعامل مع البيانات دون إجراء أي تغيير في منطق عمل البرنامج. إمكانيّة إجراء تغيير جذري لنوع الخدمة التي نستخدمها لتخزين البيانات دون تغيير يُذكر في منطق العمل. سأخوض مباشرةً في كيفية اعتماد هذا النموذج في تطبيقنا هذا. حيث سنحتاج إلى استخدام واجهة واحدة Interface مع صنف واحد يُحقّقها. لتنعش ذاكرتك حول الواجهات انظر هذا الدرس. لنبدأ الآن في بناء هذا التطبيق وذلك في الفقرة التالية. بناء التطبيق ابدأ بإنشاء مشروع جديد من النوع Blank App (Xamarin.Forms Portable) وسمّه ContactsApp ثم أبق فقط على المشروعين ContactsApp (Portable) و ContactsApp.Droid كما وسبق أن فعلنا في هذا الدرس. من نافذة مستكشف الحل Solution Explorer انقر بزر الفأرة الأيمن على المشروع ContactsApp واختر من القائمة التي ستظهر الخيار Add ثم من القائمة الفرعية الخيار New Folder لإضافة مجلّد جديد. سمّ هذا المجلّد بالاسم Entities، وبعد أن يظهر في نافذة الحل Solution Explore انقر عليه بزر الفأرة الأيمن واختر الخيار Add ومن القائمة الفرعية اختر Class. ستظهر نافذة تسمح لك بتعيين اسم لهذا الصنف. اختر الاسم Contact له. هذا الصنف هو حجر البناء الأساسي لهذا البرنامج والذي يمثّل منطق العمل فيه. احرص على جعل محتويات الملف Contact.cs كما يلي: namespace ContactsApp.Entities { public class Contact { public int Id { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public string Tel { get; set; } public string EMail { get; set; } public string Hobbies { get; set; } public override string ToString() { return string.Concat(FirstName, " ", LastName); } } } يحتوي الصنف Contact كما يظهر من الشكل السابق على البيانات الأساسيّة التي تحتاجها أيّة جهة اتصال، بالإضافة إلى خاصيّة الهوايات Hobbies التي قد تبدو غريبة قليلًا بالنسبة لجهة اتصال. انقر مرّة أخرى بزر الفأرة الأيمن على المشروع ContactsApp ثم اختر من القائمة التي ستظهر الخيار Add ثم من القائمة الفرعية الخيار New Folder لإضافة مجلّد جديد. سمّ هذا المجلّد بالاسم Abstract، وبعد أن يظهر في نافذة الحل Solution Explore انقر عليه بزر الفأرة الأيمن واختر الخيار Add ومن القائمة الفرعية اختر New Item. ستظهر نافذة تسمح لك بتعيين نوع العنصر المراد إضافته. اختر واجهة Interface وعيّن الاسم IContactsRepository لها. واحرص على أن تكون محتويات الملف IContactsRepository.cs كما يلي: using System.Threading.Tasks; using System.Collections.ObjectModel; using ContactsApp.Entities; namespace ContactsApp.Abstract { public interface IContactsRepository { Task<ObservableCollection<Contact>> GetContactsAsync(string firstName, string lastName); Task<bool> AddContactAsync(Contact contactToAdd); Task<bool> UpdateContactAsync(Contact contactToUpdate); Task<bool> DeleteContactAsync(Contact contactToDelete); } } تُستَخدَم الواجهات عمومًا عندما نرغب بتجريد Abstraction الأمور وجعلها عموميّةً وفي ذلك فائدة كبيرة في جعل الشيفرة البرمجيّة أكثر قابليّة للفهم ولإعادة الاستخدام. وهذا سبب إضافة هذه الواجهة إلى المجلّد Abstract. لا تحتوي الواجهات على أيّة شيفرة برمجيّة كما نعلم، فكل ما تحتويه هو عبارة عن تصاريح لتوابع يجب تحقيقها ضمن أيّ صنف يرغب بتحقيق هذه الواجهة. تحتوي هذه الواجهة باختصار على العمليّات الأساسيّة التي يحتاجها تطبيقنا لإنجاز المهام المنوطة به وهي: الحصول على جهات الاتصال حسب الاسم والكنية GetContactsAsync، وإضافة جهة اتصال جديدة AddContactAsync، وتحديث جهة اتصال موجودة مسبقًا UpdateContactAsync، وحذف جهة اتصال DeleteContactAsync. أمّا سبب وجود الكلمة Async في كلّ من هذه التوابع فهو للإشارة إلى أنّه يُفترض بها أن تستخدم تقنيّة البرمجة غير المتزامنة Asynchronous Programming التي تحدثنا عنها في هذا الدرس. المثير في الأمر أنّ هذه الواجهة لا تهتم بمكان وجود البيانات أو كيفيّة الحصول عليها والتعامل معها. إنّما تهتم فقط بما يحتاجه التطبيق وبشكل مجرّد. سنكرّر الآن نفس العمليّة لإضافة مجلّد جديد ضمن المشروع ContactsApp.cs واسمه Concrete وهو الذي سيحتوي على الصنف الذي سيحقّق الواجهة IContactsRepository السابقة. انقر بزر الفأرة الأيمن على هذا المجلّد واختر Add. ومن القائمة الفرعية اختر Class. سمّ هذا الصنف بالاسم MemoryContactsRepository واحرص على أن تكون محتوياته كما يلي: using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using System.Collections.ObjectModel; using ContactsApp.Abstract; using ContactsApp.Entities; namespace ContactsApp.Concrete { public class MemoryContactsRepository : IContactsRepository { private ObservableCollection<Contact> contacts; public MemoryContactsRepository() { contacts = new ObservableCollection<Contact>() { new Contact() { Id=1, FirstName = "Ahmad", LastName="Saeed", Tel="123456", EMail="admin@example.com", Hobbies="Swimming" }, new Contact() { Id=2, FirstName = "Mahmood", LastName="Maktabi", Tel="852136", EMail="info@example.com", Hobbies="Reading" }, new Contact() { Id=3, FirstName = "Mazen", LastName="Najem", Tel="987456", EMail="it@example.com", Hobbies="Swimming" }, new Contact() { Id=4, FirstName = "Sawsan", LastName="Hilal", Tel="741258", EMail="sales@example.com", Hobbies="Writing, Reading" }, new Contact() { Id=5, FirstName = "Musab", LastName="Aga", Tel="357159", EMail="admin@example.com", Hobbies="Sport" } }; } public async Task<ObservableCollection<Contact>> GetContactsAsync(string firstName, string lastName) { throw new System.NotImplementedException(); } public async Task<bool> AddContactAsync(Contact contactToAdd) { throw new System.NotImplementedException(); } public async Task<bool> UpdateContactAsync(Contact contactToUpdate) { throw new System.NotImplementedException(); } public async Task<bool> DeleteContactAsync(Contact contactToDelete) { throw new System.NotImplementedException(); } } } الأمر الملفت للنظر هنا أنّ بيانات جهات الاتصال موجودة ضمن هذا الصنف بالفعل وتحديدًا ضمن بانيته. وهي مخزّنة ضمن المتغيّر contacts وهو معرّف على مستوى الصنف ومن النوع العمومي ObservableCollection الذي سنتحدّث عنه في الدرس التالي. يكفي الآن أن تعرف أنّه عبارة عن مجموعة عناصرها كائنات من النوع Contact وهي تُفيد في التطبيقات التي تُستخدَم فيها البرمجة غير المتزامنة. من غير الواقعي بكل تأكيد وجود البيانات مخزّنة في الصنف بهذه الطريقة، فالمفترض أن تكون ضمن قاعدة بيانات محليّة أو بعيدة أو حتى ضمن ملف عادي. في الواقع تبرز هنا قوّة نموذج المستودع Repository في عزل أسلوب الحصول على البيانات عن البرنامج الفعلي. من الواضح أيضًا أنّ التوابع الموجودة هنا تحتوي في الحقيقة على شيفرة برمجيّة تؤدّي إلى رمي الاستثناء NotImplementedException وذلك لتذكرينا بعدم جاهزيتها بعد. سيبدو مستكشف الحل في نهاية المطاف شبيهًا بالشكل التالي: الخلاصة هذا الدرس هو المقدّمة لتطبيق جهات الاتصال الذي سنتابع بناءه على مدى الدرسين التاليين. تناولنا في هذا الدرس فكرة التطبيق الأساسيّة، وتوضيح فكرة نموذج المستودع Repository من خلال بناء واجهة تمثّله بالإضافة إلى صنف يحقّقها. سيمكننا من خلال هذا الصنف (صنف المستودع) التعامل مع بيانات موجودة ضمن ذاكرة التطبيق فقط. ورغم كون هذا الأسلوب غير واقعي، إلَّا أنّه ضروري في تبسيط الأمور وجعلها أسهل للفهم. كما أنشأنا صنف يمثّل جهة الاتصال في التطبيق. ورأينا ماهية العلاقة بينه وبين صنف المستودع، من خلال الاستدعاءات إلى التوابع الموجودة ضمن الصنف الأخير. حقوق الصورة البارزة محفوظة لـ Freepik
  5. يمكننا أن نستنتج وظيفة تطبيق الصور Photos من اسمه ، حيث يقوم التطبيق بشكل عام بالتعامل مع الصور من حيث نقلها واستيرادها وترتيبها وغير ذلك من المهام المتعلقة بهذا المجال. عندما نفتح البرنامج سنلاحظ مجموعة من الخيارات. الشريط العلوي لنافذة التطبيق الجهة اليمنى: خانة للبحث في الصور، وأيقونة لمشاركة الصور، وأيقونة لإضافة المشاريع. الجهة الوسطى: تبويبات رئيسية للتطبيق (الصور/ المشاركة/ الألبومات/ المشاريع). الجهة اليسرى: أدوات أو أيقونات لطريقة عرض نافذة الصور: فالأول من جهة اليمين لتكبير حجم عرض الصور أو تصغيره، والسهمين المتجهين يمينا ويسارا لإظهار الصور حسب الأشهر أو السنة، وهكذا. تبويب الصور photos هو التبويب الذي يعرض جميع الصور التي تم استيرادها عن طريق التطبيق، إما عن طريق جهاز آخر أو عن طريق سحب الصور وإفلاتها في التطبيق. وعند رغبتنا بالحصول على صور محددة يمكننا البحث عن اسم الصورة أو حتى المنطقة التي تم تصوير الصور فيها أو البحث بتاريخ التقاط الصورة ونحو ذلك من خيارات الصور التي يتعرف عليها التطبيق. أو يمكن البحث يدويا دون الاستعانة بخانة البحث بتصفح الصور عن طريق تحريك السهم للأسفل إلى أن نصل للصور المطلوبة. إذا اخترنا إحدى الصور ستظهر لنا ثلاث أيقونات: أيقونة تشغيل العرض عند اختيار علامة التشغيل، ستظهر لنا نافذة تحتوي على مجموعة من الطرق أو المواضيع themes لعرض الصور، وحتى تختفي الموسيقى التي ستعمل تلقائيا مع النوع الذي سيقع اختيارك عليه، يمكنك تحديد الصوت الذي ترغب به من قائمة music والتي ستظهر لك الأصوات المحفوظة في جهازك في مكتبة الصوتيات في برنامج iTunes . عندما تضغط على زر play slideshow لتشغيل الشرائح سيفتحها لك في نافذة منفصلة، حيث يمكنك مشاهدة الصور أو إيقاف العرض أو الخروج منه. أيقونة زر الإضافة (+) أيقونة علامة الزائد (+) تحتوي بالمقابل عددً من الخيارات: -الخيار الأول: هو لإنشاء ألبوم للصور Album ، باختيارك له ستظهر نافذة صغيرة تحتوي على عدد الصور التي سيتم إضافتها، ونوع الألبوم. اخترنا هنا ألبوم جديد new Album ، إن كان لديك ألبوم قد أنشأته مسبقا يمكنك إضافة الصور إليه بدلا من إنشاء ألبوم جديد، وإن لم يكن كذلك فأبق الاختيار على الألبوم الجديد ثم اختر له اسما. - الخيار الثاني: هو smart album الألبوم الذكي، حيث يمكنك إنشاء ألبوم حسب الخيارات التي يوفرها التطبيق، كأن يجمع لك جميع الصور التي تم تصويرها في تاريخ معين أو مكان معين، وهكذا. ويظهر لك ثلاثة خانات بمجموعة من الخيارات لتسهيل انتقاء الصور المطلوبة من قبل التطبيق، إضافة لخانة علوية لكتابة اسم الألبوم. بقية الخيارات سنتعرض لها لاحقا في تبويب المشاريع. أيقونة مشاركة الصور وذلك عن طريق الخدمة السحابية الخاصة بالصور iCloud photo sharing والتي سنتحدث عنها بعد قليل، أو عن طريق تطبيقات أخرى كالبريد وتطبيق الملاحظات وتطبيق الرسائل وغيرها. تبويب المشاركة shared لتفعيل مشاركة الصور عن طريق iCloud photo sharing سنختار خيار البدء بالمشاركة start sharing الموجود وسط الشاشة. ستظهر لنا نافذة منبثقة سنقوم باختيار آخر عبارتين: خيار تدفق الصور My photo stream هذا الخيار سيسمح لك بانتقال صورك بين أجهزتك المختلفة (الأجهزة المصنعة من شركة Apple)، فعندما تقوم بتصوير صورة بجهازك الآي فون ستجد أن الصور ستنتقل في ألبوم أو قسم مستقل يدعى تدفق الصور الخاص بي my photo stream . تجد الألبوم في تبويب الألبومات Albums. خيار iCloud photo sharing يظهر عند العودة لنافذة تبويب المشاركة والضغط على start sharing مجددا، حيث تظهر لك خيارات لاسم ألبوم المشاركة الذي ستشاركه، وعلامة + لإضافة الأشخاص اللذين ستشاركهم، وإضافة تعليق (اختياري). بعدها يمكنك إضافة الألبوم بالضغط على زر إنشاء create. تبويب الألبومات Albums في هذا التبويب ستجد الشاشة منقسمة لجزئيين: الجزء العلوي: عبارة عن ألبومات يقوم التطبيق بإنشائها تلقائيا حسب تصنيف الجهاز للصور، من ضمنها ألبوم تدفق الصور الذي فعّلناه من تبويب المشاركة. الجزء السفلي: يضع فيها التطبيق تلك الألبومات التي قمنا بإنشائها يدويا. تبويب المشروعات projects هذا التبويب يمكننا من خلاله إنشاء مشاريع عن طريق أيقونة الزائد في الشريط العلوي: تحدثننا مسبقا عن الخيار الأول والثاني، Albumو smart Album. بقية الخيارات فيما عدا خيار slideshow خاصة بالطباعة: book : لطباعة الصور على شكل كتاب أو مجلة حيث يمكنك ترتيب الصور واختيار الحجم المطلوب calendar :طباعة الصور على تقويم card : طباعة الصورة على بطاقة مع توفير خيارات للأحجام ونحوها prints : لطباعة الصورة كما هي دون إضافتها لبطاقة أو كتاب أو نحو ذلك. عندما تختار أحد هذه الخيارات ستجد مع كل نوع خيارات للأحجام وللتنسيق يوفرها لك التطبيق، ثم بعد أن تصل للشكل المطلوب تقوم بتقديم طلب لطباعتها مقابل مبلغ من المال. حسب معلوماتي من خلال بحثي في الشبكة فإن الخدمة ليست متوفرة في جميع الدول، إلا أنه يمكنك الحصول على المطبوعات عن طريق شركات الشحن التي تعتمد على فتح بريد أمريكي كشركة أرامكس هنا رابط يتحدث عن خدمة الطباعة من موقع شركة أبل يمكنك الاطلاع عليه إن كنت مهتما بهذه الجزئية http://www.apple.com/shop/help/print_products تبويب الاستيراد import هذا التبويب لن يظهر إلا حين توصيل هاتفك الآي فون أو أي جهاز آخر من أجهزة أبل التي يدعهما التطبيق . نلاحظ وجود شريط جديد في الأعلى بمجموعة من الأيقونات: import all new items هذا الخيار في حال رغبت أن يقوم الجهاز باستيراد جميع الصور الجديدة دون الحاجة لتحديدها يدويا بنفسك. Import selected هذا الخيار في حال رغبت باستيراد الصور التي تقوم بتحديدها فقط. Delete items after import عند وضع علامة صح على هذا الخيار فسيقوم بحذف الصور التي استوردتها توًا من الجهاز الذي استوردتها منه. في جهة اليمين ستجد علامة صح عند عبارة open photos for this device عند إزالة العلامة من عند هذه العبارة فلن يفتح التطبيق تلقائيا عن وصل جهاز جديد على المحمول. ماذا لو رغبنا بإيقاف البرنامج عن العمل تلقائيا مع جميع الأجهزة التي نوصلها في الجهاز المحمول؟ بإمكانك القيام بذلك عن طريق كتابة أمر في تطبيق محرّر الأوامر terminal والذي يعتبر بديلا عن console في نظام الويندوز. حصلت على هذه المعلومة من مقال في موقع iclarified.com . للوصول سريعا للتطبيق اضغط من لوحة المفاتيح على F4 ثم اكتب اسم البرنامج في خانة البحث ليظهر لك. انسخ هذا الأمر وألصقه في المحرّر: defaults -currentHost write com.apple.ImageCapture disableHotPlug -bool YES ثم اضغط على زر الإدخال أو المسمى بالرجوع Enter . وحينها لن يعمل التطبيق تلقائيا، ولو أردت إعادة التطبيق للفتح تلقائيا عند وصل جهازك، فانسخ نفس الأمر تماما، واستبدل كلمة YES بكلمة NO. بخصوص الهواتف أو الأجهزة التي تعمل بنظام أندرويد يمكنك نقل ملفاتك منها إلى الماك عن طريق هذا التطبيق Android File Transfer من شركة Google .
  6. ما هي تطبيقات الويب التي تعمل دون اتصال؟ يبدو الأمر من الوهلة الأولى كأنَّ هنالك تضاربًا في المفاهيم. فهل هي صفحات الويب التي تنزِّلها ثم تفتحها بعد ذلك؟ لكن التنزيل يتطلب اتصالًا شبكيًا، فكيف ستستطيع تنزيل الصفحة عندما لا تكون متصلًا؟ لن تستطيع فعل ذلك بكل تأكيد، لكنك تستطيع تنزيل الصفحة عندما تكون متصلًا بالشبكة، وهذه هي آلية عمل تطبيقات HTML5 التي تعمل دون اتصال (offline web applications). بأبسط الكلمات: تطبيق الويب الذي يعمل دون اتصال هو قائمةٌ بروابط URL التي تُشير إلى ملفات HTML أو CSS أو JavaScript أو الصور أو أيّ موردٍ آخر. تُشير الصفحة الرئيسية إلى تلك القائمة التي تُسمى «ملف manifest» الذي هو ملفٌ نصيٌ موجودٌ في مكانٍ ما على خادوم الويب، وسيقرأ متصفح الويب الذي يدعم تشغيل تطبيقات الويب دون اتصال قائمةَ روابطِ URL الموجودةَ في ملف manifest، ثم يُنزِّل تلك الموارد (resources)، ثم يُخزِّنها تخزينًا مؤقتًا محليًا (local cache)، ثم سيُحدِّث النسخ المحلية منها تلقائيًا في حال تغيرت. وعندما يحين وقت محاولتك الوصول إلى تطبيق الويب دون اتصالٍ شبكي، فسيحاول متصفحك عرض النسخة المُخزَّنة محليًا تلقائيًا. ومن هذه النقطة، سيُلقى الحِمل على عاتِقِكَ تمامًا –كمطوِّر ويب–؛ فهنالك رايةٌ (flag) في DOM تخبرك إذا كان المتصفح متصلًا بالشبكة أم لا، وهنالك أحداث (events) تُفعَّل عندما تتغير حالة الوصول إلى الشبكة (أي لو كنتَ تعمل دون اتصال، ثم توفَّر لديك بعد دقيقةٍ اتصالٌ شبكي؛ أو بالعكس). لكن إن كان تطبيقُك يولِّد بياناتٍ أو يحفظها، فالأمر متروكٌ لك لتخزين البيانات محليًا عندما لا تكون متصلًا بالشبكة ثم تزامنها مع الخادوم البعيد بعد أن تستعيد اتصالك به. بعبارةٍ أخرى، تمكّنك HTML من جعل تطبيقك يعمل دون اتصال، لكن ما يفعله تطبيقك في هذه المرحلة عائدٌ إليك تمامًا. المتصفحات التي تدعم هذه الخاصية IE Firefox Safari Chrome Opera iPhone Android 10+ 3.5+ 4.0+ 5.0+ 10.6+ 2.1+ 2.0+ ملف Manifest يتمحور تطبيق الويب الذي يعمل دون اتصال حول ملف manifest للتخزين المؤقت. إذًا ما هو ملف manifest؟ هو قائمة بكل الموارد (resources) التي يحتاج لها تطبيق الويب لكي يستطيع المستخدم الوصول إليه وهو غير متصلٍ بالشبكة. وعليك أن تُشير إلى ملف manifest باستعمالك لخاصية manifest في عنصر <html> لتمهيد الطريق لعملية تنزيل وتخزين تلك الموارد تخزينًا مؤقتًا. <!DOCTYPE HTML> <html manifest="/cache.manifest"> <body> ... </body> </html> يمكن أن يتواجد ملف manifest للتخزين المؤقت في أي مكان في خادوم الويب عندك، لكن يجب أن يُخدَّم بنوع text/cache-manifest؛ إذا كنتَ تستعمل خادوم ويب يعتمد على أباتشي (Apache)، فمكن المرجَّح أنَّ كل ما عليك فعله هو إضافة تعليمة AddType في ملف ‎.htaccess في المجلد الجذر الذي يُخدَّم منه تطبيق الويب: AddType text/cache-manifest .manifest تأكَّد أنَّ اسم ملف manifest للتخزين المؤقت ينتهي باللاحقة ‎.manifest؛ إن كنتَ تستعمل خادوم ويب آخر أو ضبطًا مختلفًا لأباتشي، فراجع التوثيق الخاص بالخادوم لمزيدٍ من المعلومات حول التحكم في ترويسة Content-Type. حسنًا، على كل صفحة من صفحات HTML أن تُشير إلى ملف manifest للتخزين المؤقت، ويجب أن يُخدَّم ملف manifest بترويسة Content-Type مناسبة. لكن ماذا يوجد داخل ملف manifest؟ ها قد بدأت الإثارة. أول سطر من أي ملف manifest هو: CACHE MANIFEST وبعد هذا السطر، ستُقسَّم جميع ملفات manifest إلى ثلاثة أقسام: قسم «explicit»، وقسم «fallback» وقسم «online whitelist». لدى كل قسم ترويسةٌ مذكورةٌ في سطرٍ خاصٍ بها؛ وإن لم يحتوي ملف manifest على أيّة ترويسات، فهذا يعني ضمنيًا أنَّ كل الموارد المذكورة في الملف موجودةٌ في القسم «explicit». لا تحاول أن تطيل التفكير في الاصطلاحات السابقة، خشية أن ينفجر رأسك من الصداع. هذا ملف manifest سليمُ البنية، ويحتوي على ثلاثة موارد: ملف CSS، وملف JavaScript، وصورة JPEG. CACHE MANIFEST /clock.css /clock.js /clock-face.jpg لا يحتوي ملف manifest السابق على ترويسات للأقسام، لذا ستكون جميع الموارد المذكورة فيه موجودة في قسم «explicit» افتراضيًا. ستُنزَّل الموارد المذكورة في قسم «explicit» وتُخزَّن تخزينًا مؤقتًا محليًا، وستُستعمَل مكان نظيراتها الموجودة على الشبكة في حال كان المستخدمُ غيرَ متصلٍ. وبهذا –وعند تحميل ملف manifest للتخزين المؤقت– سينُزِّل متصفح الويب الملفات clock.css و clock.js و clock-face.jpg من المجلد الجذر لخادوم الويب، ثم إذا أزلتَ مقبس الشبكة وأعدتَ تحديث الصفحة، فستبقى كل تلك الموارد متوفرةً دون اتصال. قسم NETWORK هذا مثالٌ أكثر تعقيدًا. لنقل أنَّك تريد من تطبيق الساعة الذي أنشأته أن يتتبع الزوار باستخدام سكربت tracking.cgi الذي سيُحمَّل ديناميكيًا في خاصية <img src>، إلا أنَّ تخزين هذا الملف تخزينًا مؤقتًا سيؤثر سلبًا على غرض ذاك السكربت (الذي هو تتبع المستخدمين آنيًا)، لذا لا يجب أبدًا تخزين هذا المورد مؤقتًا ولا يجوز أن يُتاح دون اتصال. هذه هي طريقة فعل ذلك: CACHE MANIFEST NETWORK: /tracking.cgi CACHE: /clock.css /clock.js /clock-face.jpg ملف manifest السابق يحتوي على ترويسات للأقسام، فالسطر الذي يحتوي على NETWORK:‎ هو بداية قسم «online whitelist»، والموارد المذكورة في هذا القسم لن تُخزَّن محليًا ولن تتوفر دون اتصال (محاولة تحميلها عند عدم توفر اتصال ستؤدي إلى خطأ). أما السطر CACHE:‎ فهو بداية قسم «explicit»، وبقية ملف manifest مماثلة للمثال السابق، حيث سيُنزَّل وسيُخزَّن كل مورد من الموارد المذكورة محليًا وسيُتاح للاستعمال دون اتصال. قسم FALLBACK هنالك نوعٌ آخر من الأقسام في ملف manifest: قسمfallback، الذي تُعرِّف فيه البدائل عن الموارد الموجودة على الشبكة التي –لسببٍ من الأسباب– لا يمكن تخزينها مؤقتًا أو لم يتم ذلك بنجاح. توفِّر مواصفة HTML5 حلًا ذكيًا لطريقة استخدام قسم fallback: CACHE MANIFEST FALLBACK: / /offline.html NETWORK: * ماذا يفعل المثال السابق؟ أولًا، لنأخذ مثالًا موقعًا يحتوي ملايين الصفحات مثل ويكيبيديا؛ لا تستطيع تنزيل كامل الموقع، ومن المؤكد أنَّك لا ترغب بذلك. لكن لنقل أنَّك تريد أن تأخذ جزءًا منه وتجعله متوفرًا دون اتصال؛ لكن كيف ستقرر ما هي الصفحات التي تحتاج إلى تخزينها مؤقتًا؟ ماذا عن: كل صفحة زرتها في موقع ويكيبيديا –الذي افترضنا جدلًا أنَّه يدعم التشغيل دون اتصال– ستُنزَّل وستخزَّن مؤقتًا. وهذا يتضمن كل مُدخَلة من مدخلات الموسوعة التي زرتها، وكل صفحة نقاش (أي المكان الذي تتناقش فيه عن مُدخَلة معيّنة)، وكل صفحة تحرير (أي تلك الصفحة التي تُجري فيها تعديلاتٍ إلى مُدخلةٍ ما). هذا ما سيفعله ملف manifest السابق: لنفترض أنَّ كل صفحة HTML (صفحة المُدخلة أو النقاش أو التعديل أو تأريخ الصفحة) في ويكيبيديا تُشير إلى ملف manifest السابق؛ فعندما تزور أي صفحة تُشير إلى ملف manifest فسيقول متصفحك: «مهلًا، هذه الصفحة جزءٌ من تطبيق الويب يعمل دون اتصال، لكن هل أعرف شيئًا عن هذا التطبيق؟» إن لم يُنزِّل متصفحك ملف manifest المُحدَّد من قبل قط، فسيهِّيء «مخزن جديد للتطبيق» (appcache، اختصار للعبارة «application cache»)، وسيُنزِّل جميع الموارد المذكورة في ملف manifest، ثم سيُضيف الصفحة الحالية إلى مخزن التطبيق (appcache). إن كان يعرف متصفحك ملف manifest من قبل، فسيُضيف الصفحة الحالية إلى مخزن التطبيق (appcache) الموجود مسبقًا. وفي كلا الحالتين ستُضاف الصفحة التي زرتها إلى مخزن التطبيق. وهذا مهمٌ لأنَّه يعني أنَّك تستطيع بناء تطبيق ويب يُضيف الصفحات التي يزورها المستخدم تلقائيًا إلى مخزنه. فلستَ بحاجةٍ إلى وضع كل صفحة من صفحات HTML في ملف manifest للتخزين المؤقت. انظر الآن إلى قسم fallback في ملف manifest السابق، الذي يحتوي على سطرٍ وحيدٍ. القسم الأول من السطر (الذي يقع قبل الفراغ) ليس عنوان URL، وإنما نمط URL‏ (URL pattern)، حيث سيُطابِق المحرف / أي صفحة في موقعك وليس الصفحة الرئيسية فقط. فعندما تحاول زيارة صفحة ما عندما تكون غيرَ متصلٍ بالشبكة، فسيبحث متصفحك عنها في مخزن التطبيق (appcache)، فإن وجد المتصفحُ الصفحةَ في مخزن التطبيق (ﻷنك زُرتَها عندما كنتَ متصلًا بالشبكة، ومن ثم أُضيفَت الصفحة إلى مخزن التطبيق [appcache] في ذات الوقت)، فسيعرض المتصفح النسخة المُخزَّنة من الصفحة محليًا؛ إما إذا لم يجد متصفحك الصفحة في مخزن التطبيق، فبدلًا من عرض رسالة الخطأ، فسيعرض الصفحة ‎/offline.html التي تُمثِّل القسم الثاني في السطر المذكور في قسم fallback. في النهاية، لننظر إلى قسم الشبكة (network). يحتوي قسم الشبكة في ملف manifest السابق على سطرٍ فيه محرف وحيد (*)، هذا المحرف له معنىً خاص في قسم الشبكة. وهو يُدعى «online whitelist wildcard flag» وهي طريقة منمّقة لقول أنَّ كل شيءٍ غير موجودٍ في مخزن التطبيق (appcache) سيُنزَّل من عنوان الويب الأصلي لطالما هنالك اتصالٌ شبكيٌ بالإنترنت. هذا مهمٌ لتطبيقات الويب التي تعمل دون اتصال التي لا نريد تنزيلها كل صفحاتها ومواردها، وهذا يعني أنَّه أثناء تصفحك لموقع ويكيبيديا –الذي افترضنا جدلًا أنَّه يدعم العمل دون اتصال– مع اتصالٍ بالإنترنت، فسيحمِّل المتصفح الصور ومقاطع الفيديو والموارد الأخرى المضمَّنة بشكلٍ اعتيادي، حتى ولو كانت في نطاقٍ (domain) مختلف (هذا الأمر شائعٌ في المواقع الكبرى حتى لو لم تكن جزءًا من تطبيق ويب يعملُ دونَ اتصالٍ. صفحات HTML تولَّد وتُخدَّم محليًا في تلك الخواديم، لكن الصور والفيديو تُخدَّم عبر CDN في نطاقٍ آخر). لكن دون هذا المحرف البديل (wildcard)، فسيتصرّف تطبيق ويكيبيديا الذي افترضنا أنَّه يعمل دون اتصال تصرفاتٍ غريبة عندما تكون متصلًا بالشبكة. بشكلٍ خاص: لن يستطيع تنزيل أي صور أو مقاطع فيديو مخزَّنة على نطاقٍ خارجي. هل هذا المثال كاملٌ؟ لا، لأنَّ ويكيبيديا أكثر من مجرد صفحات HTML. فهي تستعمل موارد CSS و JavaScript وصور مشتركة في كل صفحة. فيجب أن تُذكَر تلك الموارد بشكلٍ صريحٍ في قسم CACHE:‎ من ملف manifest، لكي تُعرَض الصفحات عرضًا صحيحًا وتسلك سلوكًا سليمًا عندما تُشغَّل دون اتصال. لكن الغاية من قسم fallback تكمن عندما لا تنزِّل كامل صفحات تطبيق الويب الذي يحتوي على موارد لم تذكرها بصراحة في ملف manifest. ترجمة -وبتصرّف- لفصل Offline Web Applications من كتاب Dive Into HTML5 لمؤلفه Mark Pilgrim
  7. تحدثنا في الجزء الأول من هذا الدرس عن أساسيات التخزين المحلي، وسنستمر في مشوارنا مع تطبيقات الويب التي تعمل دون اتصال، وسننشِئ مثالًا عمليًا عليها. تسلسل الأحداث تحدثنا إلى الآن عن تطبيقات الويب التي تعمل دون اتصال، وعن ملف manifest للتخزين المؤقت، وعن مخزن التطبيق (appcache) بشكلٍ مبهم، وكأن الأمر يجري بطريقةٍ سحريةٍ. حيث تُنزَّل الملفات، وتقوم المتصفحات بمهامها على أتمِّ وجه، وكل شيء يعمل عملًا سليمًا! لكننا نتحدث هنا عن تطوير تطبيقات الويب، فلا يعمل أيّ شيءٍ من تلقاء نفسه. بدايةً، لنتكلم عن تسلسل الأحداث، تحديدًا أحداث DOM. عندما يزور متصفحك صفحةً تُشير إلى ملف manifest، فسيُطلِق سلسلةً من الأحداث في كائن window.applicationCache؛ أعلم أنَّ هذا قد يبدو معقدًا، لكن ثق بي، هذه أبسط نسخة تمكنت من كتابتها والتي لا تهمل أيّة معلومةٍ مهمةٍ. 1. بعد أن يلاحظ المتصفح خاصية manifest في عنصر <html>، فسيُطلِق الحدث checking مباشرةً (جميع الأحداث المذكورة هنا ستُفعَّل في الكائن window.applicationCache)، سيُفعَّل الحدث checking دومًا، حتى لو زرتَ هذه الصفحة من قبل أو كانت هنالك صفحاتٌ أخرى تشير إلى نفس ملف manifest. 2. إن لم يتعامل متصفحك مع ملف manifest المُحدَّد من قبل… سيُطلِق الحدث downloading، ثم سيبدأ بتنزيل الموارد المذكورة في ملف manifest للتخزين المؤقت. أثناء التنزيل، سيُطلِق متصفحك الحدث progress بين الحين والآخر، الذي يحتوي على معلوماتٍ عن عدد الملفات التي نُزِّلَت. بعد إكمال تنزيل جميع الموارد المذكورة في ملف manifest بنجاح، سيُطلِق المتصفح الحدث النهائي cached الذي يُشير إلى أنَّ تطبيق الويب قد خُزِّن مؤقتًا بشكلٍ كامل، وهو جاهز لكي يُستخدم دون اتصال. 3. في المقابل، إن زرتَ هذه الصفحة أو أي صفحة أخرى تُشير إلى إلى نفس ملف manifest من قبل، فسيعلم متصفحك عن ملف manifest؛ فربما خزَّن بعض الموارد في مخزن التطبيق (appcache)، وربما خزَّن كامل التطبيق. إذًا السؤال الآن هو: هل تغيّر ملف manifest منذ آخر مرة تحقق فيها المتصفح من ذلك؟ إذا كان الجواب: لا، لم يتغير ملف manifest؛ فسيُطلِق متصفحك الحدث noupdate، ولن يحتاج إلى اتخاذ خطواتٍ إضافية. إذا كان الجواب: نعم، تغيّر ملف manifest؛ فسيطلِق متصفحك الحدث downloading ويُعيد تنزيل كلُ موردٍ موجودٍ في ملف manifest. أثناء التنزيل، سيُطلِق متصفحك الحدث progress بين الحين والآخر، الذي يحتوي على معلومات عن عدد الملفات التي نُزِّلَت. بعد إعادة تنزيل كل الموارد الموجودة في ملف manifest بنجاح، سيُطلِق المتصفح الحدث النهائي updateready الذي يُشير إلى أنَّ النسخة الجديدة من تطبيق الويب قد خُزِّنت مؤقتًا بشكلٍ كامل، وهي جاهزة لكي تُستخدم دون اتصال. لكن انتبه إلى أنَّ النسخة الحديثة لن تُستعمَل فورًا، فلا تُبدَّل النسخة القديمة آنيًا، لكنك تستطيع استخدام النسخة الجديدة دون إجبار المستخدم على إعادة تحميل الصفحة باستدعاء الدالة window.applicationCache.swapCache()‎ يدويًا. إذا حدث أي شيء بشكلٍ خاطئ في أي نقطة في هذه المرحلة، فسيُطلِق متصفحك الحدث error وسيتوقف. هذه هي قائمة مختصرة بالأشياء التي قد تُسبِّب المشكلة: أعاد ملف manifest رسالة الخطأ HTTP 404 ‏(أي Page Not Found) أو 410 ‏(أي Permanently Gone). عُثِرَ على ملف manifest ولم يتغيّر، لكن فشل تنزيل صفحة HTML التي تُشير إلى الملف. تغيّر ملف manifest أثناء التحديث. عُثِرَ على ملف manifest وقد تغيّر، لكن المتصفح قد فشل بتنزيل أحد الموارد المذكورة فيه. تنقيح الأخطاء أريد أن أشير إلى نقطتين مهمتين هنا، أولهما هو شيءٌ قرأتَه لتوِّك لكنني متأكدٌ تمامًا أنَّك لم تعره اهتمامك، لذا دعني أكرره: إذا فشل تنزيل أحد الموارد الموجودة في ملف manifest تنزيلًا سليمًا، فستفشل عملية التخزين المؤقت لتطبيق الويب الذي يعمل دون اتصال بالكليّة، وسيُطلِق المتصفح الحدث error، لكن ليس هنالك أيّة إشارات إلى ماهية المشكلة. وهذا ما يجعل تنقيح (debugging) تطبيقات الويب التي تعمل دون اتصال معقدةً ومزعجةً أكثر من المعتاد. النقطة الثانية هي ليست –إذا ابتغينا الدقة التقنية– خطأً، لكنها ستبدو وكأنها علِّةٌ خطيرةٌ في المتصفح إلى أن تعلم ما الذي يجري. لهذه النقطة علاقةٌ بآليةِ تحققِ متصفحكَ فيما إذا تغيّر ملف manifest. وهي عمليةٌ تتألف من ثلاثِ خطواتٍ. هذه العملية مملةٌ لكنها مهمةٌ، لذا انتبه جيدًا لما سأتلوه عليك. سيسأل متصفحك –عبر البنى الهيكلية الاعتيادية في HTTP– إذا انتهت صلاحية التخزين المؤقت لملف manifest. وكما في بقية الملفات التي تُخدَّم عبر HTTP، سيُضمِّن خادوم الويب عندك بشكلٍ اعتيادي بعض المعلومات حول الملف في ترويسات HTTP. بعض تلك الترويسات (Expires و Cache-Control) تخبِر متصفحك كيف يُسمَح له بتخزين الملف مؤقتًا دون سؤال الخادوم إذا تغيِّر أم لا. لا علاقة لهذه النوع من التخزين بتطبيقات الويب التي تعمل دون اتصال؛ وهو يحدث تقريبًا لكل صفحة HTML أو صفحة أنماط CSS أو سكربتٍ ما أو صورةٍ أو أي موردٍ آخر على الويب. إذا انتهت صلاحية ملف manifest المؤقت (وفقًا لترويسات HTTP الخاصة به)، فسيسأل متصفحُك الخادومَ إذا كانت هنالك نسخةٌ جديدةٌ من الملف؛ فإن وجِدَت، فسيُنزِّلها المتصفح. وللقيام بهذا، سيُرسِل متصفحك طلبية HTTP التي تتضمَّن تاريخ آخر تعديل لملف manifest المُخزَّن مؤقتًا، وهو نفسه الذي أرسله الخادوم في جواب HTTP ‏(HTTP response) في آخر مرّة نزَّل فيها متصفحك ملف manifest. إذا قال خادوم الويب أنَّ ملف manifest لم يتغير منذ ذاك الوقت، فسيُعيد الخادوم حالة 304 (أي Not Modified). أكرِّر أنَّ هذا لا علاقة له بتطبيقات الويب التي تعمل دون اتصال، وهو يحدث لكل نوع من أنواع الموارد الموجودة في الويب. إذا ظنَّ خادوم الويب أنَّ ملف manifest قد تغيّر منذ ذاك التاريخ، فسيُعيد الحالة HTTP 200 (أي OK) متبوعةً بمحتويات الملف الجديد بالإضافة إلى ترويسات Cache-Control جديدة وتاريخ جديد لآخر تعديل، لذا ستعمل الخطوتان 1 و 2 بشكلٍ سليم في المرة القادمة (بروتوكول HTTP جميل جدًا؛ إذ تُخطِّط خواديم الويب للمستقبل دائمًا، فإن كان على خادوم الويب إرسال ملفٍ إليك، فسيفعل ما بوسعه لكي يتأكَّد أنَّه لن يحتاج إلى إرساله لك مرتين دون داعٍ). بعد تنزيل ملف manifest الجديد، سيقارن المتصفح المحتويات مع النسخة التي نزَّلها آخر مرة. إذا كانت محتويات ملف manifest مماثلةً لمحتويات آخر نسخة، فلن يُعيد متصفحك تنزيل أيٌّ من الموارد المذكورة في الملف. قد تعترض إحدى الخطوات السابقة طريقك أثناء تطويرك واختبارك لتطبيق الويب الذي يعمل دون اتصال، على سبيل المثال، لنقل أنَّك أنشأتَ نسخةٌ من ملف manifest، ثم بعد 10 دقائق أدركت أنَّك تحتاج إلى إضافة مورد آخر إلى الملف. لا توجد مشكلة، صحيح؟ أضفت سطرًا جديدًا وجربت التطبيق، لكنه لم يعمل! إليك ما حدث: عندما أعدت تحميل الصفحة، لاحظ المتصفح خاصية manifest، وأطلق الحدث checking، لكنه لم يفعل شيئًا… أصرَّ متصفحك بعنادٍ أنَّ ملف manifest لم يتغير. لماذا؟ لأنَّ خادوم الويب –افتراضيًا– مضبوطٌ للطلب من المتصفحات أن تُخزِّن الملفات الثابتة مؤقتًا لعدِّة ساعات (وذلك عبر ترويسات Cache-Control في بروتوكول HTTP). وهذا يعني أنَّ متصفحك سيبقى عالقًا في الخطوة رقم 1 من الخطوات الثلاث السابقة. من المؤكَّد أنَّ خادوم الويب يعرف أنَّ الملف قد تغيّر، لكن متصفحك لن يحاول سؤال خادوم الويب. لماذا؟ لأنَّه في آخر مرة نزَّل متصفحك فيها ملف manifest، طلب الخادوم منه أن يُخزِّن الملف مؤقتًا لعدِّة ساعات، لكن متصفحك حاول إعادة طلب ذاك الملف بعد 10 دقائق. دعني أوضِّح لك أنَّ هذه ليست علّة وإنما ميزة. إذ يعمل كل شيءٍ كما يجب. إن لم تكن هنالك طريقة لخواديم الويب (وللخواديم الوسيطة [proxies]) لتخزين الملفات مؤقتًا، فسينهار الويب بين ليلةٍ وضحاها. لكن هذا ليس عزاءً لك بعد أن قضيت عدِّة ساعات محاولًا معرفة لماذا لم يلاحظ متصفحك أنَّ ملف manifest قد تعدَّل (من الطريف إن كنت قد انتظرت فترةً كافيةً ثم أعدتَ تحميل الصفحة فسيعمل الملف بشكلٍ سحري! ذلك لأنَّ فترة صلاحية الملف قد انتهت، كما قد حُدِّدَ لها تمامًا). هذا ما عليك فعله فوريًا: إعادة ضبط خادوم الويب عندك لكي لا يُخزَّن ملف manifest مؤقتًا عبر بروتوكول HTTP. إذا كنتَ تستعمل خادوم ويب مبني على أباتشي، فكل ما عليك فعله هو إضافة السطرين الآتيين إلى ملف ‎.htaccess: ExpiresActive On ExpiresDefault "access" التعليمات السابقة ستُعطِّل التخزين المؤقت لكل ملف في ذاك المجلد وفي جميع المجلدات الفرعية، ومن المُرجَّح أنَّك لا تريد فعل هذا في خادومٍ إنتاجي؛ لذا عليك إما أن تضع التعليمات السابقة ضمن تعليمة <Files> لكي تؤثِّر على ملف manifest فقط، أو تُنشِئ مجلدًا فرعيًا لا يحتوي إلا على ملف manifest وملف ‎.htaccess فقط. وكالمعتاد، تختلف تفاصيل الضبط من خادومٍ إلى آخر، لذا راجع توثيق خادوم الويب الذي تستعمله لتفاصيلٍ حول كيفية التحكم بترويسات التخزين المؤقت لبروتوكول HTTP. بعد أن تُعطِّل التخزين المؤقت الخاص ببروتوكول HTTP على ملف manifest، ربما تواجهك مشكلة أخرى في أنَّك قد عدَّلت في أحد الموارد التي ستُخزَّن في مخزن التطبيق (appcache) لتُستعمَل دون اتصال، لكنها بقيت تملك نفس عنوان URL في خادومك. هنا ستعترض الخطوة رقم 2 من الخطوات الثلاث السابقة طريقك. إذا لم يتغير محتوى ملف manifest، فلن يلاحظ المتصفح أنَّ أحد الموارد المُخزَّنة مسبقًا قد تغيّر. ألقِ نظرةً إلى المثال الآتي: CACHE MANIFEST # rev 42 clock.js clock.css إذا عدِّلتَ ملف الأنماط clock.css وجربت التطبيق، فلن تلاحظ وجود التعديلات التي أجريتها، وذلك لأنَّ ملف manifest نفسه لم يُعدَّل. في كل مرة تُجري فيها تعديلًا لموردٍ ما في تطبيق الويب الذي يعمل دون اتصال، فعليك أن تُعدِّل ملف manifest نفسه. وهذا بسيطٌ جدًا، فلا يلزمك إلا تغييرُ حرفٍ وحيد. أسهل طريقة وجدتها لفعل هذا هو تضمين تعليق فيه رقم النسخة أو المراجعة (revision). غيّر رقم النسخة الموجود في التعليق، ثم سيلاحظ متصفحك أنَّ محتوى الملف قد تغيّر وسيعيد تنزيل كل الموارد المذكورة فيه. CACHE MANIFEST # rev 43 clock.js clock.css لننشِئ واحدًا! هل تتذكر لعبة الضامة التي برمجناها في درس canvas ثم حسّنّاها لاحقًا بحفظنا للتحركات عبر التخزين المحلي؟ ما رأيك أن نجعل اللعبة تعمل دون اتصال. علينا أن نُنشِئ ملف manifest يحتوي على قائمة بجميع الموارد التي تحتاج لها اللعبة. حسنًا، هنالك صفحة HTML رئيسية، وملف JavaScript وحيد الذي يحتوي على شيفرة اللعبة. لا توجد صور، لأننا رسمنا كل شيءٍ برمجيًا عبر الواجهة البرمجية لعنصر canvas. وجميع أنماط CSS موجودة في عنصر <style> في أعلى صفحة HTML. ها هو ذا ملف manifest الخاص باللعبة: CACHE MANIFEST halma.html ../halma-localstorage.js كلمة عن المسارات: أنشأتُ مجلدًا فرعيًا باسم offline/‎ في مجلد examples/‎، وملف manifest السابق موجودٌ هناك في المجلد الفرعي. ولأنَّ صفحة HTML ستحتاج إلى تعديلٍ بسيطٍ لكي تعمل دون اتصال (سآتيك به بعد دقيقة)، فأنشأتُ نسخةً منفصلةً من ملف HTML، الموجودةُ أيضًا في المجلد الفرعي offline/‎، ولعدم وجود أيّة تعديلات على شيفرة JavaScript منذ أن أضفنا دعمًا للتخزين المحلي، فسأستعمل ملفات ‎.js نفسها، الموجودة في المجلد الأب (examples/‎). ستبدو المسارات كالآتي: /examples/localstorage-halma.html /examples/halma-localstorage.js /examples/offline/halma.manifest /examples/offline/halma.html نريد الإشارة إلى ملفين في ملف manifest للتخزين المحلي (‎/examples/offline/halma.manifest)، أولهما هو النسخة التي تعمل دون اتصال لملف HTML (/examples/offline/halma.html) ولأن كلا الملفين في نفس المجلد، فمن الممكن ذكره في ملف manifest دون وجود سابقة للمسار. أما ثانيهما، فهو ملف JavaScript الموجود في المجلد الأب (‎/examples/halma-localstorage.js‎)، ويجب استخدام المسارات النسبية في ملف manifest:‏ ‎../halma-localstorage.js، وهذا مشابهٌ لاستعمالك لعنوان URL نسبي في خاصية <img src>. يمكنك أيضًا استعمال المسارات المطلقة (absolute paths، تلك التي تبدأ من المجلد الجذر للموقع) أو حتى عناوين URL المطلقة (التي تُشير إلى موارد موجودة على نطاقات أخرى). علينا إضافة خاصية manifest في ملف HTML لكي تُشير إلى ملف manifest للتخزين المؤقت: <!DOCTYPE html> <html lang="en" manifest="halma.manifest"> هذا كل ما عليك فعله! عندما تزور صفحة اللعبة التي تعمل دون اتصال بمتصفح حديث، فسينزِّل ملف manifest المُشار إليه في خاصية manifest ثم سيبدأ بتنزيل جميع الموارد الموجودة فيه ويضعها في مخزن التطبيق (appcache). ومن هنا ستتولى شيفرة الصفحة الأمر في كل مرة تزور فيها الصفحة. يمكنك اللعب دون اتصال وستُخزَّن بيانات اللعبة محليًا، لذا ستستطيع أن تُغلِق اللعبة ثم تعود إليها متى شئت. كلمة أخيرة أعلنت W3C أخيرًا أنَّها ستزيل هذه الميزة من معيار HTML5، إلا أنَّ هذه العملية ستستغرق وقتًا طويلًا. ونصحت W3C باستخدام Service Workers بدلًا منها. المشكلة أنَّ ميزة Service Workers غير مدعومة من الغالبية العظمى من المتصفحات، والمتصفحات التي تتواجد فيها ميزة Service Workers تدعمها دعمًا جزئيًا فقط. تركت W3C المطورين بين المطرقة والسندان، لكنني أرى أنَّ عليك الاستمرار في استخدام هذه الميزة، مع متابعة أخبار دعم Service Workers لتنتقل إليها في المستقبل. مصادر إضافية المعايير: Offline web applications في مواصفة HTML5 توثيقٌ من صانعي المتصفحات: Offline resources in Firefox HTML5 offline application cache، التي هي جزءٌ من Safari client-side storage and offline applications programming guide الدروس التعليمية: Gmail for mobile HTML5 series: using appcache to launch offline - part 1 Gmail for mobile HTML5 series: using appcache to launch offline - part 2 Gmail for mobile HTML5 series: using appcache to launch offline - part 3 Debugging HTML5 offline application cache an HTML5 offline image editor and uploader application ترجمة -وبتصرّف- لفصل Offline Web Applications من كتاب Dive Into HTML5 لمؤلفه Mark Pilgrim
  8. إنّ أفضل شيء يفعله مدير مُنتج ما هو أن يقرّر أين تنتهي حدود مُنتجه، وأين تبدأ مهمّة مُنتج آخر. لا يستحق التطبيق كلفة الإنشاء أو التّسجيل، ناهيك عن سعر الشراء الحقيقي إذا كان الأثر الذي يُحدثه صغيرًا. وبالمثل إذا كان الأثر الذي يحدثه كبيرًا جدًّا فسيصطدم مع البرامج الموجودة مسبقًا أو تدفّق العمل workflow الذي اعتاد عليه المستخدمون بالفعل. إنّها معضلة المُنتج المعتدل، يجب عليك أن تجد المُنتج المناسب فحسب. مثال: تطبيق تعقب الوقت Time trackingيعتبر تعقّب الوقت، كحد أدنى مطلق (أي في صورته القاعدية)، مجرّد جمع قائمة من الأرقام، وإذا كان هذا هو أقصى ما يقدّمه التّطبيق فسيكون عديم الفائدة. حيث أنّ مستندات جوجل أو اكسل تقوم بهذه المهمة بالفعل. وسندرك عند هذه النّقطة أنّ البساطة مبالغ فيها، وأنّه ليس هنالك ما يمكن إضافته لتحسين التّطبيق، لا مجموعة من الخطوط، ولا خصائص HTML5 ولا المؤثّرات الصّوتيّة. وكحد أعلى، يمكن أن يشتمل تعقّب الوقت على إدارة المشاريع، الميزانيّات، المتعاقدين، قوائم الحسابات، تعقّب وصولات الاستلام، ورصد الموظّفين. إنّ التّطبيقات التي تتضمن العديد من المهام تتجاوز حدودها لتتخطاها إلى أراضي مُنتجات أخرى يعتمد عليها المُستخدم بالفعل (كـ Xero، Ballpark، Basecamp، إلخ.) إنّ المُنتجات توجد لحل المشاكل التي تحدث في تدفّق العمل، وتمتلك نقطة بداية ونقطة نهاية في ذلك التدفّق. ولكي تعرف مواقع هذه النقاط يجب أن تفهم تدفّق العمل بالكامل. لنلقي نظرة على تدفّق العمل لفريق يقوم بطلب وجبات الغداء كل يوم. إذا كنت تقوم ببناء تطبيق يساعد الفريق على طلب وجبات الغداء كل يوم، يمكن أن يكون تدفّق العمل كالتالي: يجوع أحدهم.يقوم أحدهم بإخبار بقية أفراد الفريق.تتم المناقشة حول الخروج لتناول الطعام أم القيام بالطلب.تتم مناقشة أخرى حول المكان الذي يُطلب منه.يتم تمرير قائمة بأماكن مختلفة بين الجميع.يتم التّوصل إلى قرار ما بسرعة.يُعيّن شخص ما لجمع طلبات الجميع.يقوم ذلك الشخص بالطلب.يقوم ذلك الشخص بإخبار الجميع عن وقت التسليم وكلفة الطلب.الوقت يمضي.يصل الطعام، ويؤكل.يتحقق الشخص الذي قام بالطلب من الأشخاص الذي دفعوا والذين لم يدفعوا مقابل الوجبة.تتم التّسوية المالية، أو أنّها تؤجل إلى الغد.سيتحدّث بعضهم عن الوجبة في فيس بوك أو تويتر، وبعضهم يقوم بنشر الصور على إنستجرام، وآخرون يقيمونها على Yelp.يعود الجميع إلى العمل.بإمكانك عندما تفهم تدفّق العمل بالكامل أن تركّز على المجموعة الجزئية الأكثر إشكالًا التي يحلّها مُنتجك، أو بدلًا من ذلك، التركيز على الجزء الذي بإمكانك جعله أكثر متعة وإثارة للاهتمام. هنالك مقال للمطّور Don Dodge بعنوان "هل مُنتجك عبارة عن فيتامين أم مسكّن ألم" والذي يناقش فيه الفرق بين الخيارين. من أين يجب أن تبدأ؟إنّ الخطوة الأولى لمُنتجك يجب أن تتحدّد عندما تستطيع إضافة قيمة. بالنسبة للمثال أعلاه، ربّما تكون هذه هي الخطوة الرابعة. يمكن في البدايات المبكّرة أن تقوم ببناء مُنتجات للدردشة أو البريد الإلكتروني، ونادرًا ما تكون البداية فكرة جيّدة. من الأمثلة الواقعية على ذلك تطبيق TripIt. يقوم هذا التطبيق بتقديم الحلول لإدارة الرحلات. يمكن أن تكون خطوة البداية لهذا التطبيق هي البحث عن الرحلات، لكنّ TripIt لم يستطع إضافة قيمة في هذه الحالة. إنّ أوّل مرحلة يمكنهم إضافة قيمة عندها هي بعد أن يتم الحجز. قام TripIt بإضافة حل رائع وذلك بفهم تدفّق العمل بالكامل. إنّ آخر أمر يمكن أن يحدث قبل أن يستطيع TripIt إضافة قيمة هو أن "يفتح المستخدم رسالة تأكيد الحجز"؛ هذه هي المرحلة الأولى التي يستطيع فيها TripIt إضافة قيمة لكي يبدأ مع تلك الرسالة ويقوم بالاستيراد من هناك. وبالمثل، يبدأ إنستجرام عن طريق استيراد شبكات التواصل الاجتماعي الخاصة بك، أو يبدأ تطبيق تعقّب الوقت عن طريق استيراد المشاريع من Basecamp. إنّ واجهات التّطبيقات الجيّدة وميزات الاستيراد تساعد المستخدمين على الاستمتاع ببداية سهلة التّشغيل. أين يجب أن تتوقف؟ يجب أن تقوم ميزانيّتك، سواءً كانت ميزانية الوقت أو المال، بحد نطاق المُنتج من دون تحديده (أي من دون تحديد/تعريف نطاق المُنتج) . يجب أن تحدّد الميزانية الكبيرة كيفية حل المشكلة وليس عدد المشاكل التي تعالجها، حيث أنّه من شبه المستحيل أن تحاول معالجة تدفّق العمل بأكمله من البداية حتّى النهاية ولجميع فئات المستخدمين. يجب أن يتوّقف مُنتجك عندما: تسعى وراءه شركات رائدة ومعروفة في السوق (مثل PayPal، IMDB، Expedia) وأنت لست على استعداد للمنافسة.تنتهي المرحلة التالية من المنتج بالعديد من الطرق المختلفة باستخدامه من قبل العديد من الفئات المختلفة من المستخدمين. مثلًا، محاولة معالجة الرواتب في تطبيق تعقّب الوقت قد تكون صعبة أو معقّدة.تشتمل المرحلة التالية على مستخدمين نهائيين end users مختلفين عن المستخدمين في المراحل السابقة، مثلًا المدراء، المحاسبين، إلخ.يصل إلى مرحلة لا تستطيع فيها تقديم أي قيمة.حدد وألغ الخطوات عديمة المعنى إذا انتهى المستخدم من استخدام تطبيقك وكانت الخطوة التالية التي سيقوم بها هي تنزيل ملف لإرساله إلى عبر البريد الإلكتروني، فإن هذه خطوة عديمة المعنى. إذا كان المستخدم سيقوم بتصدير بياناته الماليّة كملف CSV ومن ثم يقوم بتحميله وتحويله إلى ملف XLS ثمّ إرساله عبر البريد الإلكتروني إلى المحاسب، فهذه الخطوة عديمة المعنى أيضًا. وإذا تم الانتهاء من مشروع، ثم يتم تنزيل جميع الملّفات، تحويلها إلى ملفات مضغوطة ثم إرسالها إلى العميل للأرشفة، فهذه خطوة عديمة المعنى أيضًا. غالبًا ما يكون البريد الإلكتروني مصدرًا للخطوات عديمة المعنى التي نادرًا ما تحمل معلومات كافية ("قام شخص ما بنشر تعليق")، أو أنّها لا تحيل إلى إجراءات بديهيّة (التأكيد، التأشير كـ "محلول"، إلخ). وبشكل عام، يجب أن تتكون لديك صورة واضحة عن الخطوة التي يجب إزالتها في الحالة التي يقوم في المستخدم بالنقر خلال سلسلة من الخطوات دون أخذ فكرة معيّنة أو اتخاذ قرار معيّن على طول المسار. الخطوات المستقبليةحاول دائمًا أن تكمل النواقص وتسد الثغرات في المُنتج قبل توسيعه. إنّ الانتقال من البرامج الجاهزة إلى برامج الاشتراك subscription هو بمثابة مكافأة للمُنتجات الموثوقة والكاملة، وليس المُنتجات مُفرطة الخصائص والمليئة بالأخطاء. إنّ توسيع المُنتج ليقوم بحل مشاكل أكبر يمكن أن يعود بفوائد كبيرة، لكن لا يمكن لذلك أن يحدث إلّا إذا كان الأساس راسخًا. فإذا كان مُنتجك الأساسي ليس شاملًا، ستؤدي إضافة ميزات إضافية إلى جعل الأمور أسوء. كثيرًا ما يُكتب هذه الأيام حول تحري البساطة، لكن هناك التباس في الأمر؛ حيث أنّ هنالك فرق أساسي بين تبسيط المُنتج وعمل مُنتج بسيط. إنّ تبسيط المُنتج يؤكّد على إزالة جميع التعقيدات غير الضّرورية لكي يستطيع كل المستخدمين حل مشاكلهم بأكبر كفاءة ممكنة. أمّا عمل مُنتج بسيط يعني التركيز على مجال معين واختيار أصغر المجموعات الجزئية من تدفّق العمل حيث يمكن للمُنتج أن يقدم قيمة. ولذلك ينطوي المُنتج الفعّال القاعدي MVP على خطر تصنيفه كحلّ جزئي أو نقطي point solution، أو حتّى أسوء من ذلك؛ اعتباره "خاصيّة وليس مُنتج". لذلك يجب أن تراعي "أين ترسم الخط" عندما تقوم ببناء مُنتج بسيط. ترجمة -وبتصرّف- للمقال Where to Draw the Line لصاحبه: Des Traynor. حقوق الصورة البارزة: Designed by Freepik.
  9. إنّ إتقان تخطيط صفحات الويب بدون إتقان لغة CSS سيكون كمن يحاول السباحة على أرضٍ جافة، ولكن على عكس السباحة التي عندما تتقنها تبقى معك طول الحياة فإنّه لا يوجد مرحلة يمكنك عندها التوقف عن التعلم وتقول أنّك أتقنت CSS فهذه اللغة تتطور بسرعة يومًا بعد يوم. كما أنّ تعلم وإتقان هذه اللغة سيكون أكثر تحديًا بسبب وجود إختلافات في كيفية تطبيق ودعم هذه اللغة من قبل المتصفحات (حتى بين الإصدارات المختلفة للمتصفح نفسه). ولمدة تناهز العشر سنوات كان مطوّرو الويب يتصارعون ويعانون من الدعم المتشتت وغير المتناسق لخصائص CSS3 في كل إصدار جديد للمتصفحات. ولكن لنتفق على شيء ما وهو أنّ إتقان CSS شيء لا بد منه لأي مطور ويب جيد. وفي هذا المقال سوف نأخذكم في جولة لنتعرف على مبادئ CSS في تخطيط الصفحات وسوف نبدأ من التقنيات التي ظهرت في CSS2 وانتهاءً بآخر ما ظهر في CSS3. ملاحظة: سوف نستخدم HTML5 وSass في هذا المقال. ويمكنك الحصول على الشيفرات البرمجية كاملة من هنا. إحدى حالات الاستخدامإنّ من أفضل الطرق لتعلم أي تقنية هو أن يكون هناك حالة استخدام محددة تحاول دعمها أو أنّك تبحث عن حل لمشكلة ما. وحتى نهاية هذا المقال سنركز على حالة استخدام بمجموعة من المتطلبات. ستكون حالة الاستخدام التي سنعمل عليها عبارة عن تخطيط لتطبيق ويب (Web App) مع بعض السلوكيات المتغيرة/الديناميكية (dynamic)، بحيث سيكون هناك عناصر ثابتة في الصفحة مثل الترويسة (header) والتذييل (footer) وقائمة رئيسية (navigation) وقائمة فرعية (sub-navigation) وقسم محتوى قابل للتمرير(scrollable content). ستكون المتطلبات الخاصة بتخطيط الصفحة كما يلي: التخطيط الأساسي:الترويسة، التذييل، قائمة رئيسية وقائمة فرعية وهذه العناصر ستبقى ثابتة عند التمرير (scroll).سوف تشغل القائمة الرئيسية والقائمة الفرعية أي مساحة عمودية فارغة.سوف يشغل قسم المحتوى المساحة المتبقية في الصفحة وسوف يحتوي على منطقة قابلة للتمرير.السلوكيات المتغيرة/الديناميكية:سوف تحتوي القائمة الرئيسية على أيقونات فقط بشكل افتراضي، ولكن يمكن لها أن تتمدد لتحتوي على بعض النصوص (وأيضًا تتقلص/تنطوي لتظهر الأيقونات فقط مرة أخرى). اختلافات في تخطيط الصفحة:ستحتوي بعض الصفحات على قائمة فرعية بجانب القائمة الرئيسية والبعض الآخر لا. استخدام تقنيات CSS2 هذا هو تخطيط HTML5 الذي سوف نستخدمه: <body class="layout-classic"> <header id="header"></header> <nav id="nav"></nav> <aside id="subnav"></aside> <main id="main"></main> <footer id="footer"></footer> </body> 1. الموضعة الثابتة (position: fixed)في CSS2 يمكنك الحصول على عناصر ثابتة في الصفحة (مثل الترويسة، التذييل...الخ) عن طريق توظيف نموذج تخطيط يَستخدم الموضعة الثابتة (يستخدم position: fixed). سوف نستخدم أيضًا الخاصية z-index لنتأكد بأنّ العناصر الثابتة سوف تظهر فوق جميع العناصر الأخرى في الصفحة، بحيث تقوم هذه الخاصية بتحديد مكان العنصر إمّا أعلى أو أسفل عنصر آخر، فالعناصر التي تحتوي على قيمة z-index كبيرة سوف تظهر فوق العناصر التي تحتوي على قيمة z-index أقل. هناك شيء مهم يجب عليك تذكره وهو أنّ خاصية z-index لن تعمل إلا بوجود خاصية position، أي أنّك إذا استخدمت خاصية z-index على أحد العناصر ولكنك لم تستخدم خاصية position على نفس العنصر فإنّ خاصية z-index لن تعمل. وبالنسبة لنا، فسوف نستخدم القيمة 20 (وهي أعلى من القيمة الافتراضية) حتى نُبقي العناصر الثابتة فوق العناصر الأخرى في الصفحة. وسوف نستخدم خاصية width ونعطيها القيمة 100% وهذا سيسمح للعناصر بالتمدد أفقيًا بالقدر الذي تستطيعه. #header, #footer { position: fixed; width: 100%; z-index: 20; } #header { top: 0; height: 5em; } #footer { bottom: 0; height: 3em; }هذا بالنسبة للترويسة والتذييل، ولكن ماذا بالنسبة للقائمة الرئيسية (nav#) والفرعية (subnav#)؟ 2. تقنية التوسع/التمدد في CSSبالنسبة للقائمة الرئيسية (nav#) والفرعية (subnav#)، سوف نستخدم تقنية تسمى بتقنية التمدد (CSS Expantion) بحيث تُستخدم هذه التقنية على العناصر التي تحتوي على الخاصية position: fixed (بحيث يبقى العنصر ثابت في الصفحة) أو الخاصية position: absolute (بحيث يتم موضعة العنصر بناءً على أقرب عنصر حاوي يحتوي على الخاصية position بقيمة غير القيمة static). يمكن الحصول على تمدد رأسي/عمودي (vertical) باستخدام الخاصيتين top و bottom وإعطائها قيم محددة بحيث يتمدد العنصر عموديًا ليستخدم المساحة العمودية المتبقية وفقًا لتلك القيم، أي أنّ ما نقوم به هو ربط الجزء العلوي للعنصر بمسافة محددة من الجزء العلوي للصفحة وكذلك ربط الجزء السفلي للعنصر بمسافة محددة من الجزء السفلي للصفحة مما سيؤدي إلى تمدد العنصر ليشغل المساحة العمودية بين هاتين النقطتين (العلوية والسفلية). ونفس الأمر ينطبق على التمدد الأفقي بحيث نستخدم الخاصيتين left و right ونعطيها قيم محددة بحيث يتمدد العنصر أفقيًا ليشغل المساحة الأفقية المتبقية وفقًا لتلك القيم. وبالنسبة لنا في هذه الحالة فإننا نريد أن نستخدم التمدد العمودي: #nav, #subnav { position: fixed; top: 6em; /* ترك مسافة فوق الترويسة */ bottom: 4em; /* ترك مسافة تحت التذييلة */ z-index: 20; } #nav { left: 0; width: 5em; } #subnav { left: 6em; /* leave 1em margin to right of nav */ width: 13em; }3. الموضعة الإفتراضية/الساكنة (static)سوف نستخدم الموضعة الساكنة لموضعة منطقة المحتوى القابلة للتمرير، بحيث تظهر العناصر وتتموضع بالترتيب كما تظهر بالتدفق الطبيعي للمستند (كما تظهر في ملف HTML)، وبما أنّ جميع العناصر الأخرى في الصفحة متموضعة بشكل ثابت فإنّ هذا العنصر سيكون هو العنصر الوحيد الذي يظهر وفقًا للتدفق الطبيعي للمستند. ونتيجة لذلك فكل ما نحتاجه لموضعة العنصر بشكل مناسب هو استخدام الخاصية margin حتى لا يحصل تداخل بينه وبين العناصر الأخرى الثابتة (الترويسة، التذييل والقائمتين الرئيسية والفرعية): #main { margin: 6em 0 4em 20em; }وبهذا نكون قد أتممنا متطلبات التخطيط الأساسي باستخدام CSS2 وبقي علينا أن نهتم بأمر المتطلبات الإضافية الخاصة بالسلوكيات المتغيرة/الديناميكية. 4. السلوكيات المتغيرة/الديناميكية باستخدام تقنيات CSS2ذكرنا سابقًا بأنّ القائمة الرئيسية سوف تحتوي على أيقونات فقط بشكل افتراضي، ولكن يمكن لها أن تتمدد لتحتوي على بعض النصوص (وأيضًا تتقلص/تنطوي لتظهر الأيقوانات فقط مرة أخرى). لنبدأ أولًا بإعطاء القائمة الرئيسية عندما تكون متمددة عرضًا (width) بقيمة 5em زيادة على عرضها الرئيسي (أي يصبح عرضها عندما تتمدد 10em)، وسوف نقوم بذلك عن طريق إنشاء class باسم "expanded" بحيث يمكننا ديناميكيًا (باستخدام الجافاسكربت) إضافته أو إزالته من القائمة الرئيسية: #nan { left: 0; width: 5em; &.expanded { /* Sass notation */ width: 10em; } } يمكنك بالأسفل رؤية كود الجافاسكربت (jQuery في حالتنا هذه) الذي سوف نستخدمه لإضافة أو إزالة الـclass الذي يحمل الاسم "expanded" عندما يقوم المستخدم بالنقر على أيقونة القائمة: $('.layout-classic #nav').on('click', 'li.nav-toggle', function() { $('#nav').toggleClass('expanded'); });يمكن الآن للقائمة الرئيسية أن تتمدد أو تتقلص بكل سهولة. ولكن هناك مشكلة صغيرة وهو أنه عندما تتمدد القائمة الرئيسية فإنها سوف تتداخل مع القائمة الفرعية وهو ما لا نريده بكل تأكيد، ولذلك سوف نحتاج إلى تعديل الأمور قليلًا. يمكنك الآن رؤية واحدة من المشاكل/القيود في CSS2، فسوف نحتاج الآن إلى كتابة العديد من الأكواد الخاصة بقيم العناصر المتموضعة بشكل ثابت، ونتيجة لذلك فسوف نحتاج إلى تعريف classes باسم "expanded" إضافية حتى نسمح للعناصر الأخرى بأن تتموضع لاستيعاب القائمة الرئيسية عندما تتمدد، وبذلك سوف نحتاج إلى كتابة المزيد والمزيد من الأكواد الإضافية. #subnav { left: 6em; width: 13em; &.expanded { left: 11em; /* تحريكها لليمين */ } } #main { margin: 6em 0 4em 20; z-index: 10; &.expanded { margin-left: 25em; /* تحريكها لليمين */ } }سوف نحتاج أيضًا إلى إضافة أكواد جافاسكربت إضافية لإضافة أو إزالة الـclass "expanded" لتلك العناصر عندما يقوم المستخدم بالنقر على القائمة الرئيسية. $('.layout-classic #nav').on('click', 'li.nav-toggle', function() { $('#nav, #subnav, #main').toggleClass('expanded'); });سيكون كل شيء أفضل الآن. 5. اختلافات تخطيط الصفحة باستخدام تقنيات CSS2كنا قد ذكرنا مسبقًا بأنّ بعض الصفحات لن تحتوي على قائمة فرعية. ولنكون أكثر دقة فإننا نريد للقائمة الفرعية أن تختفي عندما يضغط المستخدم على أيقونة "المستخدمين" (users) الموجودة في القائمة الرئيسية. سوف نبدأ أولًا بإنشاء class بالاسم "hidden" وفيه الخاصية display: none: hidden { display: none; }كما أننا سنستخدم الجافاسكربت لإخفاء القائمة الفرعية وذلك عن طريق تطبيق الفئة "hidden" على هذه القائمة عندما يقوم المستخدم بالنقر على أيقونة "المستخدمين" (users): $('#nav.fa-user').on('click', function() { $('#subnav').toggleClass('hidden'); });وبهذا يمكن للعناصر أن تختفي عند النقر على أيقونة "المستخدمين" ولكن المساحة التي كانت تحتلها سوف تبقى غير مستخدمة بدلًا من أن تقوم العناصر الأخرى باستخدام تلك المساحة. وحتى نحصل على السلوك المطلوب عندما نقوم بإخفاء القائمة الفرعية فإننا سوف نستخدم المحدد المجاور(adjacent sibling selector) وهو يأتي على شكل إشارة الجمع +. 6. المحدد المجاوريُستخدم المحدد المجاور لتحديد عنصرين واختيار العنصر الثاني الذي يأتي مباشرة بعد العنصر الأول. فعلى سبيل المثال، سيقوم الكود التالي باختيار العنصر الذي يحمل ID بقيمة main والذي يأتي مباشرة بعد العنصر الذي يحمل ID بقيمة subnav: #subnav + #main { margin-left: 20em; }استخدمنا الكود في الأعلى لإعطاء العنصر main# الخاصية margin-left: 20em فقط إذا كان هذا العنصر يأتي مباشرة بعد العنصر subnav#. ولكن عندما يتمدد العنصر nav# (بحيث يتم إضافة الفئة expanded إلى العنصر main# بناءً على الكود الذي كتبناه سابقًا) فإننا نريد للخاصية margin-left أن تحتوي على القيمة 25em. #subnav + #main.expanded { margin-left: 25em; }وأمّا إذا كانت القائمة الفرعية subnav# مخفية فإننا نريد للخاصية margin-left الخاصة بالعنصر main# أن تحتوي على القيمة 6em: #subnav.hidden + #main { margin-left: 6em; }ملاحظة: واحدة من مساوئ استخدام المحدد المجاور هو أن الـDOM سوف يحتوي دائمًا على العنصر subnav# حتى لو كان غير ظاهر في الصفحة. وأخيرًا، إذا كان العنصر subnav# مخفيًا وnav# متمددًا فإننا نريد الخاصية margin-left للعنصر main# بأن تكون بالقيمة 11em: #subnav.hidden + #main.expanded { margin-left: 11em; }خاتمةكل شيء إلى الآن يظهر في مكانه الصحيح من دون الحاجة إلى استخدام أكواد جافاسكربت كثيرة، ولكن يمكنك ملاحظة أن الكود يمكن أن يكون كبيرًا ومعقدًا إذا ما أردنا إضافة المزيد من العناصر إلى الصفحة. لاحظ أيضًا أنّه باستخدام CSS2 سيكون هناك الكثير من الأكواد لموضعة كل شيء في مكانه المناسب. لذلك سوف نقوم في الدرس القادم باستخدام بعض تقنيات CSS3 الجديدة وإعادة تخطيط الصفحة باستخدام تلك التقنيات. ترجمة -وبتصرّف- للمقال CSS Layout Tutorial: From Class+ic Approaches to the Latest Techniques لصاحبه Laureano Martin Arcanio.