Posts Tagged MVC

5: ربط المعطيات باتجاهين AngularJs -Two way binding

السلام عليكم ورحمة الله وبركاته
سنتابع اليوم العمل على تطبيق angularJs لنستعرض المزيد من الميزات الرائعة التي يقدمها لنا اطار عمل AngularJs
سنضيف ضمن هذه الحلقة بعض الميزات التي تتيح للمستخدم ان يتحكم بترتيب العناصر ضمن قائمة الهواتف.Two_Way_Data_Binding
يتم تحقيق عملية الترتيب الديناميكي عبر اضافة خاصية جديدة لنموذج المعطيات, وربطها مع موجه التكرار angularJs Repeater directive, ونترك باقي المهمة للسحر الذي تتميز به عملية ربط المعطيات ضمن angularJs لتقوم بالمطلوب.

بالاضافة إلى صندوق البحث, سنضيف في اعلى التطبيق قائمة منسدلة drop down menu تسمح للمستخدم بأن يتحكم بترتيب العناصر المعروضة ضمن قائمة الهواتف
تذكير:
لتشغيل المشروع ضمن المتصفح اتبع الخطوات التالية:
• عن طريق سطر الأوامر cmd ننتقل إلى المجلد الذي يحوي المشروع
• ثم نكتب التعليمة التي تقوم بتشغيل السيرفر
Npm start
• ما ان يتم تنفيذ التعليمة حتى يعمل السيرفر على البورت 8000
http://localhost:8000/app/
• ويصبح بإمكاننا استعراض التطبيق عن طريق المتصفح

لتحميل تعديلات كود هذا الدرس من ال GIT ادخل التعليمة التالية ضمن سطر الاوامر الخاص ب git كما اشرنا في الدروس السابقة
Git checkout –f step-4
سيتم ادراج التعديلات المهمة على الكود ادناه. بإمكانك ان ترى الفروقات الكاملة بالكود من الرابط التالي على GIT GitHub.

القالب Template
App/index.html

index.PNG

اجرينا التعديلات التالية على ملف index.html

في البداية, اضفنا عنصر <select> باسم orderProp, وبالتالي يستطيع المستخدم ان يختار قيمة من القيمتين المحددتين للترتيب.

illustration.PNG

ومن ثم اضفنا إلى عملية الفلترة على العنصر الذي يحوي موجه التكرار الفلترة وفق العنصر المسمى ngProp.
يقوم في هذه الحالة Angular بإنشاء ربط معطيات باتجاهين بين العنصر الذي تم اختياره وبين نموذج المعطيات المسمى orderProp.
ومن ثم يتم استخدام orderProp كدخل للفلتر orderBy.
وكما ناقشنا ضمن مقطع ربط المعطيات سابقا, فإن اي تغير على نموذج المعطيات سوف يؤدي إلى تغير البينات التابعة له والتي يتم عرضها على الواجهة مباشرة.
عملية الفلترة تتم بهذه البساطة!! دون الحاجة إلى اضافة اي كود اخر.

المتحكم Controller

app/js/controller.js

controller

  • كما نلاحظ, فإننا قد قمنا بتعديل نموذج المعطيات phones باضافة خاصية جديدة تدعى age إلى معلومات كل هاتف من الهواتف, تستخدم هذه الميزة لترتيب الهواتف بحسب العمر age – الخاصية التي تمت اضافتها.
  • كما اننا اضفنا سطر آخر إلى كود المتحكم, والذي نحدد عبره القيمة الافتراضيية ل orderProp لتكون في البداية مساوية لage – اي الترتيب بحسب خاصة age.

الفرصة الآن سانحة للحديث عن ربط المعطيات ثنائي الاتجاهtwo-way data-binding .
لاحظ بأنه عند تحميل التطبيق ضمن المتصفح, فإن العنصر “Newest” من القائمة المنسدلة يتم اختياره بشكل تلقائي.
ويعود لذلك بسبب اسنادنا القيمة age إل orderProp ضمن المتحكم.
وبالتالي فإن عملية الربط تتم بالاتجاه من نموذج المعطيات model إلى واجهة المستخدم UI.
الآن, في حال قمت باختيار “Alphabetically” من القائمة المنسدلة, سيتم عندها تحديث النموذج بالاضافة إلى تحديث قائمة الهواتف المعروضة. هذا يعني بأن ربط المعطيات يتم بهذا الاتجاه الآخر ايضا – من واجهة المستخدم UI إلى نموذج المعطيات model.

تجارب

  • سنقوم هنا بإزالة العبارة التي تحدد القيمة الافتراضية لترتيب العناصر orderProp 359796918من المتحكم, سنلاحظ تغيرترتيب العناصر
  • سوف نضيف ايضا الربط {{orderProp}} إلى الصفحة Index.html لنلاحظ القيمة الحالية للترتيب.
  • نعكس ترتيب العناصر عبد اضافة رمز “-“ قبل قيمة الفرز, ايلقد تعلمنا ضمن هذه الحلقة بعض المميزات المهمة والرائعة ضمن angularJs التي تختصر لنا الكثير من الوقت والكود, لننتقل إلى درس قادم نتحدث عبره عن dependency Injection. وإلى
  • ذلك الحين استودعكم الله والسلام عليكم ورحمة الله وبركاته

 المصدر

https://docs.angularjs.org/tutorial

الترجمة المصطلح
الموجه Directive
تعبير Expression
الربط Binding
سياق Context
نطاق Scope
موديول – وهو ما يشبه الحزمة Module
ربط المعطيات ثنائي الاتجاه two-way data-binding

 

,

أضف تعليق

4: الفلترة مع AngularJs

السلام عليكم ورحمة الله وبركاته

نتابع ضمن هذه الحلقة التعرف على المزيد من الميزات الخاصة بAngularJsfilter_data.png

قمنا بالكثير من التعديلات على تطبيقنا خلال الخطوة السابقة – الدرس السابق – لذا سيكون درسنا الحالي مختصرا مفيدا.

سوف نضيف امكانية بحث نصي كامل full text search, وسنرى سوية كم العملية بسيطة جدا.

ضمن هذا الدرس, سيحوي التطبيق على حقل للبحث search box. وسنلاحظ بأن محتوى قائمة الهواتف سوف يتغير بحسب القيم المدخلة ضمن حقل البحث.

تذكير

لتشغيل المشروع ضمن المتصفح اتبع الخطوات التالية:

  • عن طريق سطر الأوامر cmd ننتقل إلى المجلد الذي يحوي المشروع
  • ثم نكتب التعليمة التي تقوم بتشغيل السيرفر
    npm start
  • ما ان يتم تنفيذ التعليمة حتى يعمل السيرفر على البورت 8000
    http://localhost:8000/app/
  • ويصبح بإمكاننا استعراض التطبيق عن طريق المتصفح

site

لتحميل تعديلات كود هذا الدرس من ال GIT ادخل التعليمة التالية ضمن سطر الاوامر الخاص ب git كما اشرنا في الدروس السابقة

Git checkout –f step-3

سوف ندرج ضمن هذا الدرس التعديلات المهمة فقط. بإمكانكم الاطلاع على كافة الفروقات من الرابط التالي: GitHub

المتحكم Controller

لا يوجد أي تعديلات على المتحكم

القالب Template

App/index.html

template

كما تلاحظون, فإننا اضفنا تاغ لعنصر الادخال <input> واستخدمنا وظيفة خاصة بالفلترة جاهزة ضمن angularJs تدعى filter الهدف منها معالجة وفلترة النصوص المتولدة ضمن موجه التكرار ngRepeat وفلترتها بحسب النص المدخل ضمن الحقل النصي الذي تمت اضافته.

الكود اعلاه, يمكن المستخدم من اضافة اي ميزة من ميزات الهواتف ضمن الحقل النصي, وفلترة قائمة الهواتف بحسبها مباشرة.

يوضح لنا الكود السابق مايلي:

  • ربط المعطيات data-binding : ويعتبر اهم ميزة من ميزات angular. عندما يتم تحميل الصفحة, يربط angular اسم الحقل النصي بمتحول variable يحمل نفس الاسم ضمن نموذج المعطيات data model ويحافظ عليهما متزامنان معنا.

ضمن الكود الحالي سنلاحظ بأن المعطيات التي يتم ادخالها ضمن الحقل النصي الخاص بالبحث – والمسمى query – سيتم الفلترة بحسبها مباشرة ضمن النصوص المتولدة نتيجة موجه التكرار ng-repeater في القائمة

اي ان الحقل النصي اصبح بمثابة فلتر للقائمة, وهذا ما يقوم به الكود التالي

Phone in phones | filter:query

اي تغيرات على نموذج  المعطيات data model سوف تتسبب بتغيرات محتويات ودخل موجه التكرار, الذي بدوره سوف يعكس وبفعالية هذه التغيرات على ال DOM ليعكس بذلك حالة نموذج المعطيات.

root scop

استخدام الفلتر filter: تستخدم وظيفة الفلتر filter القيمة الموجودة ضمن الحقل الذي يحمل الاسم query لإنشاء مصفوفة جديدة تحوي فقط القيم التي تطابق تلك القيمة – قيمة البحث.

يقوم الموجه ngRepeat بشكل اوتوماتيكي بتحديث صفحة العرض كاستجابة لتغير عدد اجهزة الهاتف التي يتم اعادتها من قبل الفلترfilter.

تجارب

استعراض قيمة البحث الحالية359796918

بإمكاننا استعراض قيمة البحث الحالية المخزنة ضمن النموذج query model عبر اضافة الكود التالي ضمن صفحة Index.html

{{query}}

ونلاحظ كيف ستتغير القيمة الموجودة ضمنه مباشرة فور الكتابة ضمن الحقل المخصص للبحث.

exp 1

استعراض قيمة البحث ضمن عنوان صفحة هتمل HTML 

سنرى سوية الآن كيف بإمكاننا عرض قيمة الحقل المربوط مع نموذج المعطيات ‘query’ ضمن عنوان صفحة هتمل HTML.

سنضيف الكود التالي ضمن تاغ العنوان في صفحة هتمل HTML

<title> Google phone gallery : {{query}} </title>

ثم نقوم باعادة تحميل الصفحة ضمن المتصفح, ونكتب ضمن حقل البحث, ولكن!! نلاحظ عدم تحديث عنوان الصفحة بحسب الكتابة. السبب في ذلك لان ‘query’ model يقع خارج النطاقscope , لأن ng-controller=’PhoneListCtr”  – والتي تحدد نطاق angularjs – تقع ضمن تاغ body وبالتالي لا تشمل ما غير ذلك.

<body ng-controller=PHoneListCtr”>

إذا اردتم ان يتم ربط نموذج الخاص بالمتحول query مع تاغ العنوان <title>, عندها يتوجب تحريك مكان الموجه ngController من موضعه الحالي إلى تاغ <html> ليشمل بذلك كل عناصر الصفحة.

<html ng-app=”phonecatApp” ng-controller=”PhoneListCtrl”>

تأكدوا من اجازة الموجه ng-cntroller من ضمن تاغ <body> بعد نقله إلى موضعه الجديد.

الآن اعيدوا تحميل الصفحة, ولاحظوا تغير عنوان الصفحة كلما تغيرت محتويات حقل البحث المسمى query.

ستلاحظون عند بداية تحميل الصفحة, بأنه ولأجزاء من الثانية يتم اظهار النص {{query}} للمستخدم. لنتجنب هذه المشكلة يوجد هنالك حل أفضل, ويمكن عبر استخدام موجه ngBind أو ngBindTemplate, وهما غير مرئيان للمستخدم عند تحميل الصفحة.

<title ng-bind-template=”Google Phone Gallery: {{query}}” > Google Phone Gallery</title>

 

الآن كل شيء على ما يرام.

سنتوقف في هذا الدرس فقط عند هذه الميزة الرائعة وسهلة الاستخدام ضمن angularJs

وإلى لقاء قريب ضمن الدرس القادم لنتابع ضمنه الحديث عن مزايا angular عبر متابعة الخطوات المتبقة ضمن تطبيقنا الحالي

وإلى ذلك الحين استودعكم الله والسلام عليكم ورحمة الله وبركاته

المصدر

https://docs.angularjs.org/tutorial

الترجمة المصطلح
الموجه Directive
تعبير Expression
الربط Binding
سياق Context
نطاق Scope
موديول – وهو ما يشبه الحزمة Module

 

,

أضف تعليق

3:القوالب الديناميكية مع AngularJs

القوالب الديناميكية Angular Dynamic template

pic_angularالسلام عليكم ورحمة الله وبركاته

نتابع معكم ضمن الدرس الثالث تعلم angularJs عبر مثال تطبيقي

كما نذكر, فإننا وصلنا في الدرس السابق إلى تشغيل تطبيق ويب يحوي على تعابير expression يتم تقييمها واظهار نتيجتها على الصفحة

{{‘yet’ + ‘!’}}

أما الآن, ولكي نظهر لكم قوة و قدرة angularJs على تحسين كود هتمل HTML , فإننا سوف ننشأ صفحة هتمل HTML ستاتيكية غير ديناميكية, ومن ثم سوف نرى كيف بإمكاننا تحويل هذه الصفحة إلى قالب template يستخدمه angular ليعرض بشكل ديناميكي بعض النتائج لمجموعة من المعطيات.

اي باختصار سوف نحول صفحة ستاتيكية مكتوبة بهتمل HTML إلى صفحة ديناميكية فقط عبر اضافة كود AngularJs إليها.

في هذه المرحلة, سوف تحتاج إلى اضافة بعض المعلومات الاساسية عن الهواتف الخلوية إلى صفحة هتمل HTML.

بعد ذلك سوف تحوي الصفحة على قائمة بمعلومات حول هاتفين.

سيتم ادراج التعديلات المهمة على الكود ادناه. بإمكانك ان ترى الفروقات الكاملة بالكود من الرابط التالي على GIT GitHub.

app/index.html:

static page.PNG

الآن, حان الوقت لتحويل هذه الصفحة الستاتيكية إلى صفحة ديناميكية – عبر اضافة AngularJs.

هنالك عدة طرق لتنسق عبرها الكود ضمن تطبيقك. أما بالنسبة لتطبيقات angular, فإننا نشجع استخدام MVC – Model-View-Controller Design Pattern لتنسيق وتنظيم الكود وبهدف عصر العناصر بشكل عملي ومنظم.

مع الاخذ بعين الاعتبار الفكرة السابقة, سنبدأ بإضافة كود angular و javascript مراعين اثناء ذلك التنظيم الذي يوزع الكود بين نموذج معطيت Model و View صفحات للاظهار و متحكم Controller.

 

سيتم الآن توليد قائمة بمعلومات الهواتف الثلاثة بشكل ديناميكي من المعطيات.

نحضر النسخة المتوافقة من الكود مع هذا الدرس من Git عبر التعليمة التالية :

git checkout –f step-2

ستلاحظون بأنه قد تم تحميل نسخة مختلفة من الكود ضمن المشروع angular-phonecat

سيتم ادراج التعديلات الاساسية ادناه, اما اذا رغبتم باستعراض كافة الفروقات, بإمكانكم الاطلاع عليها من GitHub.

الصفحات والقوالب views and templates

ضمن angular تعتبر الصفحة view عبارة عن انعكاس لنموذج المعطيات model عبر قالب هتمل HTML template.

هذا يعني بإنه ما إن يتغير نموذج المعطيات model حتى يحدث angular النقاط المرتبطة binding points به مباشرة والتي بدورها تحدث صفحة الاظهار view.

فيما يلي صفحة الاظهار view التي تم انشائها بواسطة angular

app/index.html:

ng-repeat

قمنا باستبدال قائمة معلومات الهواتف الستاتيكية من صفحة هتمل بموجه ngRepeat وتعبيرين angular expression:

  • الخاصية ng-repeat=”phone in phones” المتواجدة ضمن تاغ <li> عبارة عن موجه تكرار خاص ب angular
    Angular repeater directive
    يخبر موجه التكرار هذا angular بإن ينشأ عنصر <li> لكل هاتف من الهواتف ضمن القائمة وذلك باستخدام تاغ <li> بمثابة قالب.
  • التعابير الواردة ضمن الاقواس المجعدة المضاعفة
    {{phone.name}} {{phone.snippet}}
    سيتم استبدالها فيما بعد بالقيم الناتجة عنها

كما نلاحظ بأننا قد قمنا بإضافة موجه جديد يدعى ng-controller, والذي يقوم بربط المتحكم PhoneListCtrl controller بتاغ <body>.

 

إن التعابير المتواجدة ضمن الأقواس المجعدة المضاعفة {{phone.name}} {{phone.snippet}} تشير إلى مواقع الربط binding points ضمن الكود, والتي تشير إلى معطيات ضمن النموذج model الخاص بتطبيقنا, والمتواجد تحت المتحكم PhoneListCtrl controller.

ملاحظة:

تم تحديد النموذج angular model عبر استخدام الكود التالي ng-app=’phonecatApp’ , حيث أن phonecatApp يمثل اسم نموذجنا.

والنموذج سيحوي بدوره على المتحكم phoneListCtrl.

tutorial_02.png

 النموذج والمتحكم Model and Controller

نموذج المعطيات data model (في حالتنا عبارة عن مصفوفة من الهواتف )

كما نلاحظ من الصورة اعلاه, بأننا عن طريق الموجه ng-app نقوم بتحديد النطاق الجذر root scope لتطبيق angular

اما الموجه ng-controller فيحدد نطاق الموجه controller scope ضمن تطبيق angular

حيث ان المتحكم controller هو ببساطة عبارة عن باني constructor function يأخذ $scope كمعامل:

app/js/controllers.js:

controller

كما نلاحظ من الكود اعلاه, بأننا قد صرحنا عن المتحكم الذي يدعى PhoneListCtrl وسجلاه ضمن موديول angularJs المسمى ب phonecatApp.

ملاحظة :

الموديول – module – عبارة عن شيء يشبه الحزمة ضمن جافا java package, ويستخدم بمثابة حاوية container لتجميع عدة امور ضمن اطار واحد.

لاحظ بأن الموجه ng-app ( الموجود ضمن تاغ <html>) يحدد اسم الموديول phonecatApp الذي سيتم تحميله فور تهيئة تطبيق angular.

بالرغم من ان المتحكم لا يقوم بالكثير في الوقت الحالي, ولكنه وكما سنرى فيما بعد يلعب دور رئيسي بالعمل.

يسمح لنا المتحكم controller بإنشاء عملية ربط المعطيات data-binding بين النموذج model وصفحة العرضview.

نلخص عملية الربط بين صفحات العرضpresentation , والمعطيات data, ومنطق الربط بين المكونات كما يلي:

  • الموجه ngController – الموجود ضمن تاغ <body> – يشير إلى اسم المتحكم, PhoneListCtrl (موجود ضمن ملف جافاسكريبت js).
  • يربط المتحكم PhoneListCtrl بين معطيات الهواتف وبين المتغير الذي يدعى $scope –نطاق – والذي تم ادخاله ضمن تابع المتحكم controller function. إن المتغير الذي يدعى “نطاق” scope بمثابة سليل اولي من نطاق الجذر root scope الذي قمنا بإنشاءه بمجرد تعريف التطبيق ng-app.
    إن نطاق المتحكم controller scope متاح لكل نقاط الربط المتواجدة ضمن ما تشمله تاغ <body ng-controller=”PhoneListCtrl”>

 

النطاق Scope

يعتبر مفهوم النطاق scope ضمن angular من المفاهيم الاساسية والمهمة جدا.

من الممكن النظر للنطاق scope على انه بمثابة الصمغ الذي يمكن كل من القالب template والنموذج model والمتحكم controller من ان يعملوا مع بعضهم البعض.

scope

يستخدم angular النطاقات scopes جنبا إلى جنب مع المعلومات الواردة في القالبtemplate, ومع نموذج المعطيات data model, والمتحكم controller بحيث يحافظ على الفصل بين صفحات الواجهة وبين نموذج المعطيات, ومع الحفاظ على التزامن.

اي كما ذكرنا هو عبارة صلة الوصل والصمغ بين المكونات المختلفة والتي تساعدنا على الحفاظ على فصلها والتنظيم بينها.

اي تغيير يطرأ على على النموذج model ينعكس على صفحات العرض view, واي تغيير يطرأ على صفحات العرض view ينعكس بدوره على النموذج model .

لتعلم المزيد عن النطاقات angular scopes, بالامكان الاطلاع على الرابط التالي:

angular scope documentation.

 

تجارب :

359796918

  • سنضيف ربط اخر إلى صفحة html, كما يلي:
    <p> Total number of phones: {{phones.length}} </p>

     

  • سننشأ خاصية جديدة ضمن النموذج model property ضمن المتحكم, ونربطها ضمن القالب كما يلي:
    $scope.name = “World”;
    نربطها ضمن صفحةhtml كما يلي
    <p> Hello, {{name}}!</p>
    الآن اعد تحميل الصفحة f5, ولاحظ العبارة “Hello, World!”
  • نضع الكود التالي في صفحة html
    <table>
    <tr>th> row number </th></tr>
    <tr ng-repeat=”I in [0, 1, 2, 3, 4, 5, 6, 7]”><td> {{i}}</td></tr>
    </table>

عند استعراض الصفحة سيظهر لنا مايلي

page preview

الخلاصة:

اصبح لدينا الآن تطبيق ويب بصفحات ديناميكية باستخدام angularJs فقط!

وتطبيقنا الحالي يتألف من العناصر الاساسية لأي تطبيق يعمل وفق MVC

  • Model نموذج المعطيات
  • Controller المتحكم
  • View صفحات العرض

كما لاحظنا استطعنا عبر خطوات بسيطة ومنظمة تحويل صفحة html ثابتة إلى صفحة ديناميكية بفضل استخدام قوالب angular

سنكتفي بهذا القدر عند هذه الحلقة, وإلى لقاء قريب في الحلقة القادمة التي سوف سنرى فيها كيف بإمكاننا اضافة امكانية البحث إلى تطبيقنا الديناميكي.

وإلى ذلك الحين استودعكم الله والسلام عليكم ورحمة الله وبركاته

 

الترجمة المصطلح
الموجه Directive
تعبير Expression
الربط Binding
سياق Context
نطاق Scope
موديول – وهو ما يشبه الحزمة Module

 

 

 

,

أضف تعليق

2: تهيئة تطبيق AngularJs

السلام عليكم ورحمة الله وبركاته

نتابع ما بدأنا به في الحلقة السابقة من سلسلة تعلم angularJs وفق مثال تطبيقي

خلال هذه الحلقة, سوف تطلعون على اهم ملفات المصدر المتواجدة ضمن مشروعنا angularJs phonecat.

pic_angular.jpg

قبل أن نبدأ, تأكدوا من اعداد بيئة التطوير, وتنصيب كل الأمور المطلوبة كما هو موضح في الدرس السابق.

ضمن المسار التالي : anugular-phonecat, نفذوا التعليمة التالية:

Git checkout –f step-0

تقوم هذه التعليمة بإعادة مساحة العمل الحالية إلى الخطوة صفر من التطبيق

اي تعود إلى نسخة اولية من التطبيق – احد فوائد انظمة ادارة النسخGIT versioning system

سنكرر هذه التعليمة بالمستقبل ضمن المراحل التي سنمر بها ضمن دروسنا, والذي سنغيره فقط ضمن التعليمة هو رقم المرحلة.

طبعا هذا سيودي إلى ضياع اي تعديلات تقومون بإجرائها على الملفات ضمن مسار التطبيق.

كما شرحنا في الدرس الأول, يجب ان تقوموا بتنصيب الملفات المتعلقة بالتطبيق عبر التعليمة التالية:

 npm install

لكي تشغلوا التطبيق عبر المتصفح, افتحوا اداة سطر الأوامر command line في نافذة جديدة – او تاب جديدة, ومن ثم نفذوا التعليمة التالية

npm start

والتي ستعمل بدورها على تشغيل سيرفر الويب.

الآن, افتحوا نافذة المتصفح browser window واكتبوا ضمن العنوان المسار التالي:

http://localhost:8000/app/

ملاحظة:

في حال كنتم قد اتبعتم الخطوات التي ذكرناها في الحلقة الاولى, قبل الانتقال الى الخطوة الحالية, قد تظهر لكن نسخة كاش من الموقع في المرحلة السابقة, وما عليكم القيام به سوى القيام باعادة تحميل الصفحة

Ctr+f5
ليتم تفريغ الكاش, واعادة تحميل الموقع وفق المرحلة الحالية.

اصبح الآن باستطاعتكم مشاهدة الصفحة ضمن متصفحكم.

لا تبدوا صفحة مسلية ابدا, ههههههه ولكنها مقبولة.

nothing here yet

كما نرى في الصورة اعلاه, فإننا نرى صفحة بيضاء تعرض العبارة التالية:

“Nothing here yet!”
والتي تمت كتابتها ضمن كود هتملHTML .

وسنعرض الكود فيما يلي ادناه.

يحوي الكود على بعض عناصر angular التي سنستخدمها مع تقدمنا ضمن هذه السلسلة التعليمية.

expression

ما اللذي يفعله الكود بالتحديد؟

الموجهng-app directive

<html ng-app>

تمثل الخاصية ng-app موجه angular ويدعى agApp (ملاحظة : تستخدم angular الاسلوب spinal-case بتسمية خواصها, كما تستخدم اسلوب camelCase لتسمية الموجهات)

يستخدم هذه الموجه ngApp directive لتحديد عنصر من عناصر هتمل HTML على انه العنصر الجذر لتطبيق angular.

يعطي هذا مطوري التطبيقات الحرية في اخبار angular عن الأجزاء من صفحة html التي يجب معاملتها على انها تطبيق angular.

اي ان هذا الموجه يحدد لنا الجزء من كود هتمل html الذي سيشكل تطبيق angular.

AngularJs Script Tag

<script src=”bower_components/angular/angular.js”>

الكود اعلاه يضمن ملف angular.js ضمن كود هتمل, وهذا الملف هو المسؤول عن تسجيل

يقوم الكود اعلاه بتحميل سكريبت angular.s التي تعتبر مسؤولة عن تسجيل الاستدعاءات callback التي يتم تنفيذها من قبل المتصفح عند تحميل صفحة هتمل Html بشكل كامل.

الأقواس المجعدة المضاعفة Double-curly

Nothing here {{‘yet’ + ‘!’}}

يمثل السطر اعلاه احد اهم امكانيتين يقدمها لنا نظام القوالب في angular

  • الربط, ويتم الاشارة إليه باستخدام الأقواس المجعدة المضاعفة double-curlies {{ }}
  • التعبير البسيط المستخدم في الربط ‘yet’ + ‘!’

 

تخبر أقواس الربط angular بأنه يتوجب عليه تقييم التعبير expression الموجود بينهما, وادراج النتيجة ضمن DOM في مكان الربط تمام.

بدلا من الاضافة إلى DOM لمرة واحدة فقط, فسوف نرى في الخطوات القادمة كيف أن عملية الربط سوف تنتج عمليات تعديل وتحديث فعالة ومستمرة كلما طرأ تعديل على التعبير المطلوب تقييمه.

تعابير angular

Angular Expression: عبارة عن كود مشابه لجافا سكريبت, يتم تقييمه من قبل angular وفق نطاق النموذج الحالي, بدل من تقييمه ضمن نطاق السياق العالم (النافذةwindow )

ما إن يتم معالجة القالب من قبل angular, حتى تحوي صفحة هتمل html العبارة التالية:

“Nothing here yet!”
Bootstrapping AngularJs App

تهيئة تطبيق angularJs

تبدأ تهيئة تطبيق angularJs بشكل اوتوماتيكي باستخدام الموجه ngApp.

هنالك ثلاثة أمور مهمة تحدث خلال عملية تهيئة التطبيق:

  • تم انشاء ال injector الذي سوف يتم استخدامه خلال عملية dependency injection.
  • من ثم سيقوم ال injector بإنشاء ال root scope – نطاق الرؤية الجذر – الذي سيصبح عبارة عن سياق النموذج ضمن تطبيقنا context for the model of our application
  • من ثم يقوم angular ب ‘compile’ لل DOM, ابتداءا من العنصر الحاوي على موجه ngApp, معالجا خلال ذلك كل الموجهات والربط الذي يجده خلال طريقه.

 

ماإن يتم الانتهاء من عملية تهيئة التطبيق, حتى يصبح مستعدا ومنتظرا للأحداث التي يقوم المتصفح بإرسالها ( مثل نقرة الماوس, ضغط مفتاح …) والتي قد تغير على النموذج model .

Two_Way_Data_Binding.png

على سبيل المثال, في حال وقع حدث ما, فإن angular يقوم بالتحقق فيما إذا سبب هذا الحدث اي تعديلات او تغييرات على النموذج model , وفي حال وجدت مثل هذه التغيرات, فإن angular سوف يعكسها على الصفحة view عبر تعديل وتحديث كل عناصر الربط المتأثرة affected binding.

بنية تطبيقنا في الوقت الحالي جدا سهلة وبسيطة.

يحوي القالب على موجه وحيد one directive, وعلى ربط وحيد وثابت static binding, ونموذجنا فارغ حاليا empty model.

سيتغير هذا الوقع قريبا!

 ملاحظة:

لا تنسوا بأن angularJs تعمل وفق MVC

  1. M: Model النموذج
  2. V: View الصفحة
  3. C: Controler المتحكم

tutorial_00.png

اذن ماهي كل تلك الملفات الموجودة ضمن مسار العمل الحالي؟

معظم الملفات الموجودة ضمن مسار العمل الحالي آتية من angular-seed project, وهذا المشروع يستخدم بشكل اساسي لتهيئة واعداد المشاريع التي ترغب باسخدام angularJs.

حيث ان مشروع seed project تم اعداده مسبقا لكي يقوم بتنصيب اطار عمل angular framework, بالإضافة إلى الأدوات ا للازمة لتطوير تطبيق ويب قياسي (عبر استخدام npm).

لأسباب تتعلق بخطة التعليم التي نسير بها ضمن هذه السلسلة التعليمية, قد قمنا بتعديل angular-seed كما يلي:

  • ازالة تطبيق المثال الجاهز
  • إضافة مجلد يحوي صور الاجهزة إلى المسار التالي :app/img/phones/
  • إضافة ملفات معطيات (بصيغة json) إلى المسار التالي: app/phones/
  • اضافة ملفات اخرى عبر json

359796918تجارب

بإمكانكم الآن تجريب تعبير جديد new expression ضمن ملف index.html , الذي بدوره سيقوم ببعض الحسابات البسيطة

<p>1 + 2 = {{ 1 + 2 }}</p>

الخلاصة

والآن وبعد ان تعلمنا بعض الأمور الاساسية عن angular وطريقة الربط التي تعتمد على تقييم التعابير expression evaluation, بإمكاننا الانتقال إلى الخطوة التالية , والتي سنضيف عبرها بعض المكونات إلى تطبيق الويب.

وهذا ما سنقوم به في الدرس القادم, الذي سيكون اكثر متعة وحركة وسنتعلم فيه الكثير عن مميزات angularJs

لا تتردوا في حال كان لديكم اي تساؤل حول ما تم عرضه لحد الآن
وإلى ذلك الحين استودعكم الله والسلام عليكم ورحمة الله وبركاته

المصدر:

https://docs.angularjs.org/tutorial

الترجمة

المصطلح

الموجه

Directive

تعبير

Expression

الربط

Binding

سياق

Context

 

,

أضف تعليق

1: AngularJs مقدمة

AngularJS-large

السلام عليكم ورحمة الله وبركاته

سوف نتطرق ضمن الحلقات القادمة إلى تعلم اطار عمل حديث ضمن البرمجة

وذلك عبر مثال تطبيقي مباشر يساعدنا على التعلم السريع

متطلبات مسبقة:

قبل البدء بمتابعة وتعلم هذه السلسلة نفترض معرفة مبسقة بالامور التالية :

  • HTML
  • CSS
  • JAVASCRIPT

ماهو AngularJs

angularJs عبارة عن اطار عمل لجافا سكريبت مفتوح المصدر Open-source, تم تطويره برعاية غوغل, ويتوقع ان يكون لاستخدامه دور اساسي ومهم في المستقبل في مجال تطوير المواقع وتطبيقات الموبايل.

يعمل angular وفق ما يعرف ب MVC اي

Slide7Model-View-Controller

وطريقة العمل هذه تجعل عملية التطوير اسهل ومنظمة اكثر من قبل

يمكن اضافته إلى صفحة هتمل html عبر استخدام تاغ <script>

لنتجاوز هذا الكلام النظري وننطلق إلى التجربة العملية التي ستوضح لنا معنى هذا الكلام السابق.

مثال عملي

المثال الذي سنشرح عبرهangularJs عبارة عن موقع يعرض كتالوج لاجهزة الهاتف

اسهل طريقة لتعلم angularJs هي عبر التطبيق العملي, وهذا ما سنقوم به ضمن هذه السلسلة التعليمية, حيث سنتدرج خطوة بخطوة لبناء تطبيق ويب يستخدم angularJs.

التطبيق الذي سنعمل عليه عبارة عن موقع يحتوى على كتالوك لعرض أجهزة اندرويد, حيث بإمكان المستخدم ان يفلتر قائمة الاجهزة المتوافرة للبحث عما يهمه, كما ان بإمكان المستخدم ان يطلع على تفاصيل اي جهاز من الأجهزة

catalog_screen.

تابعوا معنا هذه السلسلة التعليمية لكي تروا كيف أنه بإمكان angular ان يجعل المتصفحات أذكى – بدون استخدام اضافات plug-ins:

سنتعرض ضمن هذه السلسلة للنقاط التالية:

  • أمثلة على كيفية القيام بربط المعطيات في طرف العميل client-side بهدف بناء صفحات ديناميكية تحتوي على المعطيات التي تتغير مباشرة وبحسب تفاعلات المستخدم معها
    data binding to build dynamic views
  • نستعرض كيفية قيام angular بالحفاظ على الصفحات views متزامنه مع المعطيات التي تحويهادون الحاجة إلى عمليات DOM.
  • تعلم اسهل وافضل طريقة لاختبار تطبيق الويب الخاص بك

عند انتهائك من هذه السلسلة تكون قد تعلمت ما يلي :

  • بناء تطبيق ديناميكي يعمل ضمن كل المتصفحات الحديثة
  • استخدام طريقة “ربط المعطيات Data binding “ لتربط بين نموذج المعطيات data model  مع صفحاتك views.
  • نقل منطق التطبيق application logic إلى المتحكمات Controllers
  • استحضار المعطيات من السيرفر عبر استخدام angular services
  • اضافة التحريك إلى تطبيقك عبر استخدام ngAnimate
  • التعرف على المزيد من المصادر لتعلم angularJs

ستقودك هذه السلسلة التعليميه عبر الخطوات الازمة لبناء تطبيق بسيط وفعال يستخدم angularJs, بما في ذلك من كتابة الكود وتشغيله واختباره.

لننطلق

الآن سنشرح فيما يلي كيف بإمكانك ان تعد جهازك للتطوير لكي تكون جاهزا لتطبيق الخطوات معنا.

اما اذا رغبت فقط بالقراءة دون التطبيق بإمكانك تجاوز تتمة هذا الدرس.

خلال الحلقات القادمة سنتابع المثال التطبيقي نفسه وفق المراحل التالية

  • Bootstrapping
  • Static Template
  • Angular Template
  • Filtering Repeaters
  • Two-way Data Binding
  • XHRs & Dependency Injection
  • Templating Links & Images
  • Routing & Multiple Views
  • More Templating
  • Filters

ملاحظة :

لنع نعمد إلى ترجمة أغلب المصطلحات, وذلك عندما لانجد فائدة من ترجمتها , انما نذكرها ونستخدمها كما هي, كي نسهل على القارئ التعرف عليها اينما ذكرت على الانترنت

العمل مع الكود

تعتمد هذه السلسلة التعليمية على نظام الاصدارات Git versioning system, حيث تم وضع الكود على GIt.

لست بحاجة إلى ان تتعلم حول GIT لتتبع هذه السلسلة, ويكفيك فقط ان تتعليم كيف بإمكانك تنصيب GIT واستخدام اوامره.

تنصيب GIT

بإمكانك تحميل وتنصيب GIT من الموقع التالي:

  http://git-scm.com/download

ما ان تقوم بتنصيبه, حتى يصبح بإمكانك النفاذ إلى اداة الأوامر السطرية الخاصة ب GIT command line tool .

التعليمات الاساسية ضمن GIT التي سوف تحتاج إلى استخدامها هي التالية :

  1. Git clone  : تقوم هذه التعليمة بنسخ الكود المتواجد على السيرفر إلى جهازك
  2. Git checkout : تقوم هذه التعليمه باالخروج من فرع أو نسخة محددة ضمن الكود

تحميل مشروع angular-phonecat من GIT

 

لكي تنسخ الكود الخاص بالتطبيق إلى جهازك من ال gitHub استخدم التعليمة التالية :

git clone –depth=14 https://github.com/angular/angular-phonecat.git

تقوم هذه التعليمة بإنشاء مسار يدعى angular-phonecat ضمن مسارك المحلي.

يقوم الخيار –depth=14 بإخبار GIT ان يقوم فقط بسحب اخر 14 تعديل – اخر 14 نسخة تم التعديل عليها وتثبيتها, إن هذا التحديد ب 14 تعديل فقط يجعل النسخة التي ستقوم بتحميلها إلى جهازك اصغر وأسرع

الآن قم بالانتقال للمسار الجديد

cd angular-phonecat

من الآن وصعوداً, سوف نفترض بأنك تقوم بتنفيذ كافة التعليمات من المسار التالي :

Angular-phonecat

تنصيب Node.js

اذا رغبت بتنفيذ وتشغيل المثال ضمن هذه السلسلة على جهازك – سيرفرك المحلي – فأنت بحاجة ايضا إلى تنصيب  Node.js v0.10.27+  .

بإمكانك تحميل وتنصيب node.js من الرابط التالي:

http://nodejs.org/download/

تحقق من نسخة node.js التي قمت بتنصيبها عبر التعليمية التالية :

node –version

ما إن تنصب node.js على جهازك المحلي, حتى يصبح بإمكانك تحميل بقية الأدوات التابعة للمشروع angular-phonecat عبر التعليمة التالية:

npm install

تقوم هذه التعليمة بقراءة ملف package.json الموجود ضمن مجلد angular-phonecat – من المفترض ان نكون متواجدين ضمن هذا المسار حاليا – , وتقوم بتحميل الأدوات التي سنذكرها فيما يلي إلى المسار node_modules:

  • Bower – client-side code package manager
  • Http-Server – simple local static web server
  • Karma – unit test runner
  • Protractor – end to end (E2E) test runner

كما ان  تنفيذ تعليمة npm install  يتضمن بشكل اوتوماتيكي استخدام bower لتحميل اطار عمل angular ضمن المسار التالي:

App/bower_components

كما تلاحظ فإن هذه المشروع angular-phonecat قد تمت تهيئته لكي يقوم بتنصيب وتشغل كل هذه الادوات عبر سكريبتات npm. وبالتالي لا يتوجب عليك القلق حيال توافرها لديك مسبقا, لانه سيتم تحميلها وتنصبها ضمن الخطوات.

تمت تهيئة واعداد المشروع مسبقا ليعمل مع عدد من السكريبتات المساعدة الخاصة ب npm, وذلك بهدف تسهيل عملية تنفيذ التعليمات المطلوبة منك اثناء الدروس القادمة.

  • npm start : start a local development web-serverبدء تشغيل سيرفر التطوير المحلي
  • npm test : start the Karma unit test runner
  • npm run protractor : run the Protractor end to end (E2E) tests
  • npm run update-webdriver : install the drivers needed by Protractor

تنصيب الأدوات المساعدة (خياري( Install helper tools
الأدوات تتضمن

Bower, http-server, karma, Protractor modules
بالامكان تنصيب هذه الموديولات باستخدام التعليمة التالية :

sudo npm install –g

على سبيل المثال, لتنصيب bower command line  ننفذ التعليمة التالية :

sudo npm install –g bower

يجب حذف كلمة sudo  في حال كنت ضمن بيئة windows

ومن ثم يصبح بالامكان استخدام هذه الاداة مباشرة, مثال :

Bower install

تشغيل سيرفر الويب running development web server

بما ان كود تطبيق angular هو عبارة عن كود من طرف العمل client-side code, لذلك فإنه من الممكن فتحه مباشرة ضمن المتصفحات من اي نظام ملفات,  ولكنه من الأفضل ان نستخدم ويب سيرفر http.

بشكل خاص, ولأسباب أمنية, فإن معظم المتصفحات لن تسمح لجافا سكريبت ان تقوم بطلبات للسيرفر في حال تم فتح التطبيق من ضمن نظام الملفات مباشرة.

تم تهيئة مشروع angular-phonecat بويب سيرفر بسيط لاستضافة التطبيق خلال مراحل التطوير.

الآن سنقوم بتشغيل الويب سيرفر عبر التعليمات التالية :

npm start

ستقوم هذه  التعليمة بإنشاء ويب سيرفر محلي, يتصنط على البورت 8000 ضمن جهازك.

بإمكانك الآن استعراض التطبيق على المسار التالي :

http://localhost:8000/app/index.html

لتشغيل تطبيق الويب على عنوان ip مختلف او على بورت مختلف, يتوجب عليك تعديل سكريبت “start” ضمن package.json.

بإمكانك استخدام

  • -a لتحديد العنوان
  • -p : لتحديد البورت

بعد تشغيل الويب سيرفر, وفتح الرابط اعلاه, سوف تظهر لكم صفحة مشابهة للصفحة في الصورة ادناه

angular-phonecat page

الآن وبعد ان اصبحت بيئة العمل جاهزة, بإمكاننا الانطلاق للدرس القادم لكي نباشر التطبيق الفعلي والتعرف على ميزات وامكانيات angularjs

وإلى ذلك الحين, استودعكم الله والسلام عليكم ورحمة الله وبركاته

 

المصدر:

https://docs.angularjs.org/tutorial

 

المصطلح الترجمة
Data Binding ربط المعطيات
Data Model نموذج المعطيات
Controller متحكم

,

أضف تعليق

محرك سمارتي Smary Engin

facebook-group

بسم الله الرحمن الرحيم

السلام عليكم ورحمة الله وبركاته
فيما يلي شرح مبسط قمت بإعداده باللغة العربية حول سمارتي وكيفية استخدامه وفائدته , مع تمنياتي لكم بالتوفيق
وقد ارفقت الملف الحاوي على الشرح مع
هذه المدونة


سلام:
برمجة/تصميم مواقع الانترنت وهندسة البرمجيات (محرك سمارتي):

قد تبدأ ببرمجة أحد مواقع الوب , وفق تصميم ما قمت بتنجيزه , أو قام مصمم وب مختص بإنجازه لك , ولنفترض بأنك تبرمج بلغة php  , وبعد انتهاء برمجة الموقع , اضطر مصمم الموقع أن يقوم ببعض التعديلات على تصاميمه , فتجد نفسك مضطراً في أغلب الأحيان – ليس دوما وذلك بحسب المنهجية التي تتبعها في أسلوب برمجتك – إلى تعديل في الرماز الذي قمت به سابقاً ليتكيف مع التصميم الجديد , وهذه هي الحالة مع أية تعديلات قد تطرأ على التصميم ؟! فما الحل؟ وهل هذه العملية منطقية برأيك ؟؟!

نعلم بأن أحد المبادئ الأساسية في هندسة البرمجيات يكمن في عزل منطق العمل business logic   عن العرض – التصميم- presentation  . وحتى نحافظ على هذا المبدأ في عملنا فقد تم ابتكار العديد من الأدوات والبرمجيات والمكتبات  المساعدة على تنظيم عملية الرماز والمحافظة على مبادئ هندسة البرمجيات قولاً وفعلاً, ومن أشهرها سمارتي smarty  , فما هو سمارتي , وكيف يتم استخدامه والاستفادة من الفعاليات التي يتقدمها؟؟

ماهو سمارتي ؟

يعتبر سمارتي بمثابة أحد  محركات القوالب template engineالمخصصة للغة php.

وبشكل أكثر تحديداً, فهو يوفر لنا وسيلة سهلة وبسيطة لعزل منطق التطبيق application logicوالمحتوى عن العرض presentation  . وتعتبر هذه الطريقة بمثابة الطريقة المثلى في الحالات التي يكون فيها مبرمج التطبيق ومصمم القوالب شخصان منفصلان.

 

آلية العمل :

الفكرة ببساطة هي التالية:

يعتمد سمارتي ببساطة مبدأ القوالب في عمله , فبعد أن يقوم المصمم بتصميم القالب الذي يرغب أن يكون العرض فيه , يتم تضمين متحولات سمارتي ضمنه ,تلك المتحولات المسؤولة عن عرض القيم المطلوبة ضمن هذه القوالب بالقيم المناسبة وفي الوقت المناسب بالاعتماد على إسناد القيم الصحيحة والمطلوبة لها وفق منطق العمل المطلوب.

بمعنى آخر, يقوم مصمم القوالب باستخدام مزيج من تاغات html  مع تاغات القالب template tags  بهدف تشكيل عرض مستقل عن لغة البرمجة – سيتضح لنا هذا الكلام بشكل عملي عند طرح المثال البسيط بعد قليل.

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

اعداد بيئة عمل سمارتي مع مثال توضيحي بسيط :

هالك عدة أساليب مختلفة لتبدأ بتصميم موقع يستخدم سمارتي ,ولكني سأختار طريقة بسيطة وواضحة:

1:تقوم في البداية بتنزيل المجلد المضغوط الذي يحتوي على مكتبات سمارتي الأساسية اللازمة لإعداد بيئة العمل – المجلد موجود في موقع سمارتي  www.smarty.net.

2:تقوم بفك ضغط المجلد ضمن مجلد يدعى – على سبيل المثال – smarty  , ويتواجد هذا المجلد ضمن مجلد الموقع الذي تقوم ببرمجته , وبعد فك الضغط ستجد ضمن مجلد سمارتي مايلي

   /yourSiteFolder/smarty/

                          Config_File.class.php

                          debug.tpl

                          internals/

                          plugins/

                          Smarty.class.php

                          Smarty_Compiler.class.php

 

.

3:حتى يعمل سمارتي بشكل صحيح فأنت بحاجة لإنشاء 4 مجلدات ضمن مجلد سمارتي الذي انشأته سابقاً , ألا وهي

templates,templates_c,cache,configs  ,وهي مخصصة – بالترتب- لملفات سمارتي التالية

templates , compiled templates ,cached templates , config  

4:أنشأ داخل مجلد تطبيقك ملف يدعى index.phpواكتب فيه الرماز التالي:

<?php

 

// put path to Smarty.class.php

require(‘./smarty/Smarty.class.php’);

$smarty = new Smarty();

 

$smarty->template_dir = ‘./smarty/templates’;

$smarty->compile_dir = ‘./smarty/templates_c’;

$smarty->cache_dir = ‘./smarty/cache’;

$smarty->config_dir = ‘./smarty/configs’;

 

$smarty->assign(‘name’, ‘:I am Light Tiger, nice to meet you ‘);

$smarty->display(‘index.tpl’);

 

?>

5:أنشأ ملف يدعى index.tplفي مجلد templates  أي كما يلي :

/yourSiteFolder/smarty/templates/index.tpl

حرر هذا الملف ليحوي الرماز التالي:

<html>

<head>

<title>Smarty</title>

</head>

<body>

Hello, {$name}!

</body>

</html>

 

6:واخيراً ,استعرض التطبيق الذي انشأته باستخدام مستعرض الوب الموجود على جهازك

http://localhost/yourSiteFolder/index.php

وسيظهر لك النص التالي

Hello, :I am Light Tiger, nice to meet you!

وبذلك تكون قد قمت بإنشاء أول تطبيق لك باستخدام سمارتي .

لاحظ كيف تمت عملية استبدال المتحول الموجود بالقالب بالقيمة المسندة له من خارج القالب.

ما سبق كان مقدمة بسيطة لتتابع تعلم العديد من ميزات سمارتي التي توفر عليك الكثير الكثير من الجهد والوقت.

مفاهيم اساسية لمتحولات سمارتي :

 يتم تعريف متحول في سمارتي كما يلي {$smaryVariable}  حيث يخضع تعريف اسم المتحول لنفس قواعد تعريف المتحولات في php  ,ويجب أن يحاط بالأقواس التالية{}

أما عملية إسناد متحول لسمارتي فتتم عبر الاستدعاء التالي :

$smarty->assign(‘variableName’,’value’);

لعرض أحد القوالب(الموجودة ضمن مجلد القوالب ):

$smarty->display(‘templateName.tpl’);

 

لإضافة تعليق

{*this is a smarty comment that will not be displayed on the final output of the template*}

وبالإضافة إلى الكثير من التوابع والإمكانيات التي يقدمها لنا سمارتي للتحكم بعرض المعلومات.

وبذلك نكون قد قدمنا لكم شرحاً بسيطاً ومختصراً عن أحد أهم الأدوات المساعدة على تنظيم العمل وتبسيطه.              للاستزادة ولمزيد من المعلومات بإمكانكم مراجعة الموقع التالي: www.smarty.net

, , , , ,

2 تعليقان