مستوى المقال: مبتدئ


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

في هذا الموضوع سنتحدث عن عن علاقة إطار العمل ExpressJS مع الباترن NodeJS و كيفية عمل Pug as template engine 


اولا: حتى لا تكون هناك امور مبهمه و ابعاد الغيوم التي تدور حول اذهان الكثير من يريد العمل او التوجه لهذا الباترن يجب عرض بعض من الحقائق:

  • الـNodeJS ليست لغة جديدة .. انما بيئة مبرمجة بالـJS.
  • هذه البيئه تعمل في جهة السيرفر.
  • ان كنت مبرمج AngularJS or ReactJS ليس هناك سطر محدد تربط فيه بين تطبيقك الNode مع الفريموورك الذي تعمل به.
  • طريقة الربط تكون من خلال HTTP requests.
  • تستطيع التعامل مع قواعد البيانات المختلفه مباشره بالـNode مثل MySQL, MariaDB و اشهرهم في هذا المجال هي MongoDB.

 

نعود مرة اخرى للـExpressJS الذي هو يعتبر فريم وورك ابعد مما ان يقال عنه "مساعد" في تطبيقات الـNode.

بإستخدام هذا الفريم وورك الذي يعمل كذلك في السيرفر،  يتم تسهيل العمل و كمية الكود في تطبيق الـNode  بشكل كبير جدا.

مثال على تطبيق Node بإستخدام فريم وورك ExpressJS وسيتم شرح اجزائه جميعها

var express = require('express');
var app = express();

app.get('/', function (req, res) {
 res.send('Hello World!')
});

app.listen(3000, function () {
 console.log('Example app listening on port 3000!')
});

 

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

اقتباس

app.get

الشطر الثاني get هو عبارة عن نوع الـhttp request قد يكون GET, POST, DELETE, UPDATE etc ….

 

بعد ذلك يأتي المسار - لتفاصيل اكثر حول هذا الجزء الرجاء زيارة الدرس السابق.

 

نننقل الآن الى امر اخر في الـExpressJS وهو الـtemplating ( عمل الواجهات UI و استقبال البيانات المرسلة من  الـNode )

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

  1. PUG - know as Jade
  2. Mustache
  3. EJS

 

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

doctype html
html(lang='en')
  head
    title Jade
    script(type='text/javascript').
      foo = true;
      bar = function () {};
      if (foo) {
      bar(1 + 5)
      }
  body
    h1 Jade - node template engine
    #container.col
      p You are amazing
      p
        | Jade is a terse and simple
        | templating language with a
        | strong focus on performance
        | and powerful features.

 

يعادل في الHTML 

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Jade</title>
    <script type="text/javascript">
      foo = true;
      bar = function () {};
      if (foo) {
      bar(1 + 5)
      }
    </script>
  </head>
  <body>
    <h1>Jade - node template engine</h1>
    <div id="container" class="col">
      <p>You are amazing</p>
      <p>
        Jade is a terse and simple
        templating language with a
        strong focus on performance
        and powerful features.
      </p>
    </div>
  </body>
</html>

 

لمعلومات اكثر حول اللغة اطلع على موقعهم الرسمي

 

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

img1.png.bfd1811069fbafe2baedde26a966b24d.png

 

حمل الـbootstrap وانقل كل من bootstrap.min.css إلى مجلد css , انقل bootstrap.min.js إلى مجلد js

 

بعد ذلك إبدأ بتثبيت الـpackages التي سنعمل بها من خلال فتح الـterminal في مجلد myapp من خلال الاوامر التالية

$ npm install express --save
$ npm install cookie-parser --save
$ npm install body-parser --save
$ npm install mysql --save

 

افتح ملف التطبيق app.js وقم بإستدعاء هذه البكجات

var express = require('express');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var mysql = require('mysql');

 

الآن نبدأ بإعداد config فريم وورك الـExpressJS مع cookie-parser body-parser ( سنستخدمهم لاحقا )

var router = express.Router();
var app = express();
app.use(bodyParser.json({limit: "50mb"}));
app.use(cookieParser());
var urlencodedParser = bodyParser.urlencoded({
    extended: true,
    parameterLimit:50000
});
app.use("/", router);

 

نضيف امكانية استخدام ملفات الـcss, js , images etc من خلال استخدام الـmiddleware ـexpress static بإعطاء مسار وهمي لهذه الملفات

app.use('/css', express.static(__dirname + '/public/css'));
app.use('/js', express.static(__dirname + '/public/js'));

 

نرى وجود ملفات الـcss and js في مجلد public/css ولكن المسار الذي سنكتبه في الكود هو فقط css/ وليس بالضرورة ان يكون اسم المسار الوهمي ذو علاقه بالمسار الاساسي .. تستطيع ان تسميه مثلا sambosa/ و في الحقيقة هو public/css

 

تحديد نوع الـtemplate engine الذي سنستخدمه في هذا التطبيق مع تحديد مسار مجلد الـviews الذي يحتوي على صفحات الموقع او التطبيق

app.set('views', __dirname + '/views');
app.set('view engine', 'pug');

 

بعد إنشاء ملفات الـpug في إحدى الخطوات السابقه , انسخ والصق كود الصفحتين index.pug and layout.pug details.pug كلن على حدى

//layout.pug
doctype html
html
  head
    title= title
    script(src='https://code.jquery.com/jquery-3.2.1.min.js')
    link(rel='stylesheet', href='/css/bootstrap.min.css')
    script(src='/js/bootstrap.min.js')
  body
    nav.navbar.navbar-default
      .container
        .navbar-header
          button.navbar-toggle.collapsed(type='button', data-toggle='collapse', data-target='#navbar', aria-expanded='false', aria-controls='navbar')
            span.sr-only Toggle navigation
            span.icon-bar
            span.icon-bar
            span.icon-bar
          a.navbar-brand(href='/') NodeJS
        #navbar.navbar-collapse.collapse
          ul.nav.navbar-nav
            li.active
              a(href='/') Home
            li
              a(href='/details') details
            li.dropdown
              a.dropdown-toggle(href='#', data-toggle='dropdown', role='button', aria-haspopup='true', aria-expanded='false')
                | Dropdown
                span.caret
              ul.dropdown-menu
                li
                  a(href='#') Action
                li
                  a(href='#') Another action
                li
                  a(href='#') Something else here
                li.divider(role='separator')
                li.dropdown-header Nav header
                li
                  a(href='#') Separated link
                li
                  a(href='#') One more separated link
    block content
//index.pug
extends layout

block content
  .container
    h1 #{msg}
    p #{username} , welcome to the first templating tutorial
//details.pug
extends layout

block content
  .container
    .table-responsive
      h2 user table
      p This is all users we have so far
      table.table.table-bordered#example
        thead
          tr
            th Firstname
            th Lastname
            th Email
        tbody
          tr
            td John
            td Doe
            td john@example.com
          tr
            td Mary
            td Moe
            td mary@example.com
          tr
            td July
            td Dooley
            td july@example.com
  link(rel='stylesheet', type='text/css', href='https://cdn.datatables.net/v/dt/dt-1.10.15/datatables.min.css')
  script(type='text/javascript', src='https://cdn.datatables.net/v/dt/dt-1.10.15/datatables.min.js')
  script().
    $(document).ready(function() {
      $('#example').DataTable();
    });

ملاحظة: نستخدم extends layout  لكي لا نكرر الـhead في الصفحات الاخرى , مثل include في الـPHP ( في هذا الدرس ) - الاستخدام الحقيقي للـlayout هو تصميم شكل معين لصفحات معينه .. كـtemplate خاص مثلا - معلومات اكثر من خلال الرابط هنا

 

 

الأن تم تجهيز المستوى الأول من التطبيق وهو الـconfigurations , ننتقل إلى النص الآخر وهو الـroutes . اولا  route الصفحة الرئيسية سيكون كالتالي

app.get('/', function(req, res) {
    res.render('index', {
        title: 'Pug ExpressJS NodeJS Tutorial',
        username: 'abdulla',
        msg: 'Hey There!'
    })
});

 

نلاحظ ان مسار الـroute هو مجرد slash للامام .. بذلك يتم تحديد المسار الرئيسي للتطبيق, بعد ذلك res.render اي تعني response render حيث يقوم تطبيق الـNode بالأجابة من بعد عمل طلب request من طرف المستخدم , للتوضيح اكثر الـHTTP هو عباره عن بروتوكول طلب و اجابة وبذلك request and response - req, res فعند طلب العميل امر ما يجب عليه ان يحصل على شي ما في المقابل.

 

و كما موضع في الدالة اعلاه ان الـresponse هو عباره عن عمل render لملف index.pug الموجود في مجلد views مع ارسال ثلاث متغيرات title, username and msg , و طريقة استقبال البيانات في الـpug هي كالتالي ( يوجد اكثر من طريقة )

  h1 #{username}
  p Welcome to #{title}

 

خطوة اخيره لتشغيل التطبيق يجب تحديد بورت معين ولنفترض 3000

app.listen(3000, function() {
    console.log('The app is running http://localhost:3000');
});

 

افتح الـterminal داخل مجلد التطبيق myapp واكتب الامر التالي لتشغيل التطبيق

node app.js

 

افتح المتطفح على المسار

اقتباس

 

انتهى الدرس الاول .. تم من خلاله

  • عمل configuration لتطبيق الـnode الذي سنستخدمه في الدروس القادمة
  • تثبيت template engine و توصيله مع تطبيق الـNode
  • ارسال بيانات من الـNode إلى pug

 

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

 

للحصول على ملفات العمل تجدونهم في المرفقات, بعد تحميل الملف قم بفك الضغط انتقل إلى داخل المجلد واكتب الأمر التالي لتثبيت جميع الـpackages دفعة واحده

$ npm install --save

 

 

أضغط هنا لتحميل ملفات العمل anwbh-app.zip

موقع مساعد لتحويل كودات الـHTML إلى Pug 

http://html2jade.org

ANWBH

1


اراء المستخدمين


لاتوجد تعليقات لعرضها .



انشئ حساب جديد او قم بتسجيل دخولك لتتمكن من اضافه تعليق جديد

يجب ان تكون عضوا لدينا لتتمكن من التعليق

انشئ حساب جديد

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


سجل حساب جديد

تسجيل الدخول

هل تمتلك حساب بالفعل ؟ سجل دخولك من هنا.


سجل دخولك الان

Ads Belongs To This website


  •  
    بسم الله الرحمن الرحيم
    السلام عليكم ورحمة الله وبركاته
     
    في هذا الموضوع، سنستعرض الStreams، وهي عبارة عن API جديدة ورائعه تم اضافتها في التحديث الأخير للJava 8.
    باستخدام الStreams، ستستطيع معالجة بيانات الCollections كأنك تقوم بعمل Query في احد الSQL databases، وذلك بطريقة تعريفية بسيطة دون الحاجة لكتابة Loop في كل مرة تريد معالجة البيانات لتخرج بنتيجة معينة (جمع عناصر الArrayList على سبيل المثال)، وذلك بكتابة سطر برمجي واحد فقط!
    هناك ميزة أخرى أيضا للStreams، وهي امكانية تفعيل جميع أنوية المعالج لتسريع عملية تنفيذ البرنامج دون الحاجة الى كتابة سطر واحد من كلاس الThreads المزعج!
     
    ما هو الStream؟                                             
    سنذكر تاليا أهم سمات الStream في الجافا:
    تسلسل عناصر: الStream هو عبارة عن تسلسل لعناصر يتم استخلاصها من أحد المصادر (Sources) -قد تكون Array أو ArrayList الخ-، حيث يقوم الStream بـ قراءة/معالجة بيانات هذه المصادر عند الحاجة فقط المصادر: قد تكون Collection, Arrays, I/O العمليات: يدعم الStream مجموعة من العمليات (أو methods) على سبيل المثال لا الحصر: filter, map, limit, reduce, find, match تكرارات تلقائية: الStreams تدعم التكرارات التلقائية (Automatic Iterations)، أي كما قلنا سابقا، لن تكتب المزيد من الloops، كل ماعليك فعله هو كتابة سطر واحد باستعمال الStreams والجافا ستقوم بالباقي  
    إنشاء الStream                                               
    في الجافا 8، هناك طريقتان لإنشاء Stream:
    ()stream: ستنشئ ستريم تسلسلي مربوط بcollection، ولكن بدون الاستفادة من ميزة تعدد أنوية المعالج في التنفيذ ()parallelStream: ستنشئ ستريم متوازي مربوط بcollection، مستفيدًا من ميزة تعدد أنوية المعالج في التنفيذ مثال:
    List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl"); List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());  
    أهم ميثودز الStream                                         
    ()forEach:
    هذه الميثود تعطيك امكانية المرور بجميع عناصر الستريم للقيام بعملية معينة، في المثال التالي سنقوم بطباعة 10 ارقام عشوائية باستخدام forEach:
    Random random = new Random(); random.ints().limit(10).forEach(System.out::println); ()map:
    بهذه الميثود تستخدم لربط كل عنصر بالستريم مع نتيجة خاصة به. في المثال التالي سنقوم بطباعة مربعات ارقام مميزة باستخدام map:
    List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5); //get list of unique squares List<Integer> squaresList = numbers.stream().map( i -> i*i).distinct().collect(Collectors.toList()); ()filter:
    يتم استخدام هذه الميثود للتخلص من بعض عناصر الستريم بناء على شروط معينة، المثال التالي يقوم بطباعة عدد ال Strings الفارغة:
    List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl"); //get count of empty string int count = strings.stream().filter(string -> string.isEmpty()).count(); ()limit:
    هذه الميثود تستخدم للحد من حجم الستريم بدون أي شروط، في المثال التالي سنقوم بطباعة 10 ارقام عشوائية باستخدام  limit:
    Random random = new Random(); random.ints().limit(10).forEach(System.out::println);  ()sorted:
    يتم استخدام هذه الميثود لترتيب الستريم، الكود التالي يظهر كيف تقوم بطباعة 10 ارقام عشوائية مرتبة:
    Random random = new Random(); random.ints().limit(10).sorted().forEach(System.out::println);  ( لاحظ كيف أنجزنا المهمة بسطر واحد فقط، تخيل لو أردت أن تقوم بطباعة 10 ارقام عشوائية مرتبة بالطريقة التقليدية! )
     
    Parallel Processing:                                        
    هذه هي الطريقة الثانية لإنشاء الستريم الموازي (استعمال جميع أنوية المعالج لتنفيذ البرنامج) كما هو مذكور بالأعلى:
    List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl"); //get count of empty string int count = strings.parallelStream().filter(string -> string.isEmpty()).count(); لاحظ أنك تستطيع التبديل بين الStream والparallelStream بسهولة تامة.
     
    Collectors:                                                       
    نستخدم الCollectors لجمع نتائج معالجة بيانات الستريم واعادتها على شكل List.
    List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl"); List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList()); System.out.println("Filtered List: " + filtered); String mergedString = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.joining(", ")); System.out.println("Merged String: " + mergedString);  
     
    في المثال التالي، سنقوم بعمل مقارنة بين الJava 7 والJava 8 في برنامج يقوم بضم الStrings غير الفارغة. import java.util.*; public class Java8StreamTest { public static void main(String[] args) { // Java 7 approach System.out.println("Using Java 7: "); List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl"); System.out.println("List: " +strings); StringBuilder stringBuilder = new StringBuilder(); for (String string: strings) { if (!string.isEmpty()) { stringBuilder.append(string); stringBuilder.append(", "); } } String mergedString = stringBuilder.toString(); System.out.println("Merged String: " + mergedString); // Java 8 approach System.out.println("Using Java 8: "); System.out.println("List: " +strings); mergedString = strings.stream().filter(string ->!string.isEmpty()).collect(Collectors.joining(", ")); System.out.println("Merged String: " + mergedString); } }  
     
    وهنا نصل الى ختام موضوعنا، أسأل الله لي ولكم التوفيق والسداد.
    مستوى المقال: محترف

    بواسطه AMR0T , في

  • اللغة المستخدمة : swift3
    البرنامج : xcode 8
     
    السلام عليكم،
    في هذا الدرس سنتحدث عن واحدة من أهم المهارات التي تساعدك في بناء مشروعك في وقت قياسي و بنتائج ممتازة اعتمادا على استخدام مكتبات قام بإنشائها مطورون آخرون لتكون متاحة لجميع المطورين.
    لكن قبل ذلك علينا فهم بعض الأمور الأساسية للبدء  ثم سنتحدث عن طريقة تنزيل المكتبات إلى مشاريعك.
     
    الTermianl : 
    حتى تستطيع التعامل مع الملفات الخارجية يجب أن تتعلم في البداية طريقة التعامل مع الterminal
    Terminal : هي واجهة غير رسومية يمكن استخدامها لتنفيذ الأوامر العادية التي تقوم بها كإنشاء ملف أو حذفه.. الخ.
    للوصول إليها كل ما عليك فعله هو كتابة terminal في شريط البحث للوصول السريع إليها و ستظهر لك كأول نتيجة، قم بفتحها

    كما ذكرنا فإن الterminal هي واجهة غير رسومية يمكن فيها تنفيذ الأوامر عن طريق كتابتها بطريقة معينة و إهم الإوامر التي يجب التعرف عليها لهذا الدرس هي التالية : 
    cd : و هي اختصار ل (change directory ) و هي تستخدم للانتقال إلى أحد المجلدات و هي تشبه فتحك لأي مجلد من المجلدات بالطريقة العادية.
    ls : و هي تستخدم لعرض كل محتويات المجلد الموجود بداخله حاليا.
    الآن قم بفتح الterminal و قم بكتابة : 
    cd Desktop  للانتقال إلى سطح المكتب الخاص بك
    الآن قم بكتابة ls لتظهر محتويات سطح المكتب.
    ستجد أن كل الملفات و المجلدات و التطبيقات الموجودة في سطح المكتب قد تم عرضها لك في الterminal.
    هذه أهم الأمور التي يجب معرفتها فيما يخص وحدة التحكم أو الterminal للمواصلة في هذا الدرس.
     
    الCocoapod :
    و الآن حتى تتمكن من تنزيل المكتبات و الحصول عليها لابد من تنزيل أداة على وحدة التحكم للحصول على إمكانية استخدام أوامر مهمة تمكنك من إضافة المكتبات مباشرة في مشاريعك في الxcode و هذه الأداة تسمى cocoa pod و حتى تقوم بتنزيلها على الterminal الخاص بك قم بزيارة موقعهم:
    https://cocoapods.org/
    و انسخ السطر الموجود في خانة Install
    أو انسخه مباشرة من هنا : 
    sudo gem install cocoapods
    و قم بلصقه في وحدة التحكم (terminal) لديك.
    قد يطلب منك إدخال رقمك سري، قم بإدخاله ثم اضغط زر return أو enter.
    حينها سيبدأ الterminal بتنزيل الcocoa pod.
     
    ملاحظة: قد لا تظهر لك أي إشارة في الterminal تشير إلى أن البرنامج يتم تنزيله حاليا، و لكن يمكنك التأكد إذا ما نظرت إلى الزر الأحمر في الزاوية اليسرى في الشريط العلوي و الخاص بإغلاق البرنامج. حيث يفترض أن تجد بداخله دائرة سوداء و التي تشير إلى أن البرنامج يقوم بتنفيذ أحد العمليات في الوقت الحالي كما في الصورة التالية...

     
    الآن بعد اكتمال التنزيل ستزول النقطة السوداء و ستظهر لك مجموعة من التعليمات تخبرك باكتمال التنزيل كما في الصورة التالية:

    الآن يمكنك أن تتعامل مع المكتبات الموجودة و تنزيلها إلى مشروعك.
     
     
    تنزيل المكتبات
    في الجزء التالي من الدرس سنقوم بتنزيل إحدى المكتبات على مشروع xcode و سنختار JTAppleCalendar و هي تستخدم لإنشاء تقويم و استخدامه في مشروعك، و لكن لن نتحدث عن طريقة إنشاء التقويم و التعامل معه و إنما الغرض شرح طريقة تنزيل المكتبات على مشروعك و استخدام الcocoa pod لذلك يمكنك اختيار أي خيار آخر لتنزيله. و الاختيارات يمكن الوصول إليها من عدة مصادر أهمها و أشهرها الgithup حيث يمكنك البحث هناك عن كل ما تريد.
    و هنا رابط المكتبة التي سنقوم بتنزيلها إلى المشروع :
    https://github.com/patchthecode/JTAppleCalendar
    إذا لنبدأ..
    في البداية قم بإنشاء مشروع xcode جديد و سمه demo مثلا و قم بحفظه على سطح المكتب.
    -- صورة
    الآن قم بفتح الterminal..
    نريد في البداية الوصول إلى موقع المجلد الذي يحوي كل ملفات المشروع لتنزيل المكتبة في ذلك المكان و لذلك يجب علينا استخدام أمر cd ثم إضافة المسار الخاص بالمشروع للوصول إليه من خلال الterminal. ولكن يمكن استخدام طريقة أسهل من عمل ذلك يدويا و هي :
    ١- قم بكتابة cd ثم مسافة
    ٢- قم بسحب المجلد من سطح المكتب و أفلته في الterminal و ستجد أن الterminal قام بإضافة مسار المجلد تلقائيا
    ٣- اضغط enter أو return 
    الآن تم الوصول إلى داخل المجلد و يمكنك التأكد من ذلك عن طريق استعراض الملفات بداخل المجلد بالضغط على ls و ستجد أن الterminal يعرض لك ملفات المشروع الخاصة بك.
    الآن قم بكتابة الأمر التالي على الterminal :
    pod init 
    ثم اضغط enter 
    - هذا الأمر خاص بإنشاء ملف باسم pod file و هو الملف الذي يجب أن يحوي كل المكتبات التي تريد استخدامها في مشروعك. و للتأكد من أن الملف قد تم إنشاؤه قم بإدخال أمر ls مرة أخرى و يجب عليك أن تجد ملف جديد باسم Podfile أو يمكنك فتح المجلد يدويا و ستجد ذلك الملف بالداخل.
    - الآن قم بفتح ملف الpodfile حيث سنقوم بإضافة بعض الأسطر بداخله.
    - الآن عليك إضافة أسماء المكتبات التي ستقوم باستخدامها داخل هذا الملف. لكن من أين نحصل على اسم المكتبات ؟ عليك دائما أن تعود إلى التوجيهات المكتوبة من مصدر التنزيل ذاته للحصول على هذه المعلومات، لذلك قم بالعودة إلى الرابط مرة أخرى
    https://github.com/patchthecode/JTAppleCalendar
    دائما عند تنزيل المكتبات لابد من البحث على خانة الinstallation بطريقة الcocoa pod لذلك توجه إلى خانة installiation via cocoa pod و ستجد أنه يشير إلى أمر تنزيل الcocoa pod حيث قمنا بذلك مسبقا.
    و بعد ذلك يريك المحتويات التي يجب أن تكون بداخل ملف الPodFile لذلك انسخ منها الأشياء التي لا يحويها الملف الموجود عندك و هي التالية : 
    source 'https://github.com/CocoaPods/Specs.git' platform :ios, '10.0' use_frameworks! و هذه التعليمات في الأعلى ضعها في بداية الملف
     
     
    pod 'JTAppleCalendar', '~> 7.0' و هذه ضعها بدلا من : #Pods for demo  
     
    أخيرا ملف الpodFile يجب أن يبدو كالتالي :
    # Uncomment the next line to define a global platform for your project source 'https://github.com/CocoaPods/Specs.git' platform :ios, '10.0' use_frameworks! target 'demo' do # Comment the next line if you're not using Swift and don't want to use dynamic frameworks use_frameworks! pod 'JTAppleCalendar', '~> 7.0' target 'demoTests' do inherit! :search_paths # Pods for testing end target 'demoUITests' do inherit! :search_paths # Pods for testing end end مع ملاحظة النقاط التالية :
    ١- أي سطر يبدأ ب# فهو كالcomment في البرمجة لا تأثير له و لذلك لا مشكلة في حال وجود سطور إضافية من هذا النوع في ملفي أو ملفك.
    ٢- لا مشكلة إذا لم يكن ملفك يحوي السطور التالية :
    target 'demoTests' do inherit! :search_paths     # Pods for testing   end   target 'demoUITests' do     inherit! :search_paths     # Pods for testing   end  
    ٣- قد يكون هناك اختلاف في الاسم إذا لم تقم بتسمية مشروعك باسم demo و لا مشكلة في ذلك.
     
    - الآن أصبح ملف الpodfile جاهزا كل ما عليك فعله هو حفظ التغييرات التي قمت بإجرائها عليه ثم إغلاقه.
    - الآن تبقت خطوة أخيرة.. قم بالعودة للterminal و تأكد أنك ما زلت في مسار المشروع و قم بإدخال : 
    pod install 
    و اضغط enter 
    سيبدأ الآن الterminal بتحميل المكتبات التي طلبتها و عندما يكتمل التحميل سيشعرك بذلك كما في الصورة..

     
    الآن اذهب إلى ملف الxcode الذي كنت تعمل به و قم بإغلاقه ثم توجه إلى مجلد المشروع الخاص بك و ستجد أن هناك ملف xcode جديد ظهر لديك في المجلد..

    حيث أن هذا هو نفس مشروعك الذي كنت تعمل به و لكن الفرق الوحيد أنه يضم كل المكتبات التي طلبت تنزيلها.
    و الآن لتتأكد أن التنزيل تم بطريقة صحيحة.. قم بفتح الملف الجديد و اذهب إلى أي كلاس و في أعلا الملف قم بكتابة أمر :
    import JTAppleCalender إذا لم يظهر البرنامج أي مشكلة فهذا يعني أنك قمت بتضمين المكتبة في مشروعك بنجاح.
     
    ملاحظة : قد يظهر الxcode خطأ في البداية عند كتابتك لهذا الأمر.. حينها قم بمسحه و قم بعمل build عن طريق cmd+b ثم اكتب الأمر مرة أخرى و يجب أن يعمل هذه المرة
     
    إلى هنا نصل إلى نهاية الدرس و إن كنت تود تجربة عمل الcalender و استخدام المكتبة فقم بمتابعة الفيديوهات الموجودة في رابط تنزيل المكتبة و قراءة التوجيهات الموجودة هناك.
     
    إلى اللقاء في دروس قريبة قادمة بإذن الله

    مستوى المقال: متوسط

    بواسطه يعرب المصطفى , في

  • السلام عليكم ورحمة الله وبركاته..
     
    في هذا الدرس الثالث من دروس النود جي اس سنقوم بتعلم كيفية ضبط ويب سيرفر NGINX للعمل مع تطبيقات / مايكرو سيرفس الNodeJS و تحويل requests الى بورتات تطبيقاتك بشكل ضمني
     
    ماهو الnginx؟
    ببساطة هو بروكسي سيرفر عالي الاداء او ويب سيرفر،  بديل الapache.
     
    في ماذا يستخدم؟
    يستخدم في ريفيرس بروكسي للبروتوكولات HTTP, HTTPS, SMTP, IMAP, POP3 و كذلك لعمل توازن الضغط على السيرفر مثلا عندما يكون هناك عدد كبير جدا من الrequests تستطيع توزيع هذه الطلبات بالupstream بين عدة بورتات في نفس السيرفر او سيرفر خارجي مثلا اذا كان التطبيق او الموقع مبرمج بالNodeJS.

     
    بالعربي: لا تحاتي بتعرف كلشي بعد شوي.
    اولا: تثبيت الويب سيرفر.
    لتثبيت الويب سيرفر nginx اتبع التعليمات / الخطوات التالية:
    افتح التيرمنال وقم بإيقاف الapache اذا كان مثبت sudo /etc/init.d/apache stop حدث sudo apt-get update ثبت sudo apt-get install nginx تأكد ان الويب سيرفر يعمل sudo /etc/init.d/nginx status  
    ملاحظة: مهم جدا ايقاف Apache قبل تثبيت Nginx
     
    ثانيا: تشغيل تطبيقك الNode على الدومين الرئيسي.
    لتشغيل التطبيق عليك تحويل جميع الطلبات requests التي تأتي من العميل الى الPort الذي يعمل عليه التطبيق (3000 مثلا) عبر الويب سيرفر NGINX.

     
    ولعمل ذلك، افتح التيرمنال و قم بمتابعة هذه الاوامر
    اذهب لمجلد الويب سيرفر cd /etc/ngin/sites-available اكتب ls وسترى ملف بإسم default. افتح الملف للتعديل بإستخدام vim او nano وفي هذا الدرس سنستخدم الاول sudo vim default امسح كلشي واكتب هذا الكود server { listen 80 default_server; listen [::]:80 default_server; server_name www.example.com example.com; access_log /path/to/log/static_domain_access.log; location / { proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $host; proxy_set_header X-NginX-Proxy true; proxy_pass http://127.0.0.1:3000; proxy_redirect off; } }  
    اخيرا قم بإعادة تشغيل الويب سيرفر
     
    افتح المتصفح و اكتب موقعك http://www example.com
     
    Bonus
    إذا كان لديك تطبيق \ موقع كبير جدا او API و تريد عمل load balancing لتوزيع عمليه الطلبات في الصورتين ادناه الطريقة لذلك, لاحظ ان التطبيق يعمل على اكثر من بورت وكذلك الـproxy pass هو عباره عن اسم الـupstream .cluster
     
    تطبيق الNode

     
    كونفيقريشن الـNginx

    مستوى المقال: مبتدئ

    بواسطه ANWBH , في

  • بسم الله الرحمن الرحيم
    السلام عليكم ورحمة الله وبركاته
     
    في هذا الدرس سنتعرف على احد أهم الأنواع في الSwift الا وهما Structures and Enumerations.
     
    أولا: Structures أو struct                                                                                                                                                                           
    في Swift او اي لغة برمجة مشابهة، تعتبر الكلاسات حجر الأساس لمبدأ الObject-Oriented Programming.
    بالإضافة الى الكلاسات، لدينا الStructures التي تعطينا بديل مشابه للكلاسات.
    الستركتشر مشابه للكلاس، لأنه يمكن أن يحتوي على methods, properties, initializers تماما كما الكلاس، ولكن الفارق الأساسي هو ان الستركتشر يعتبر من نوع Value، والكلاسات تعتبر من نوع Reference.
     
    ما معنى Value type و Reference type؟

                                                                                      صورة توضيحية للفرق بين الRegerence والValue
    جميع الأنواع في الSwift هي اما عبارة عن Value type او Reference type. المتغيرات من نوع القيمة (Value type) -مثل متغيرات الInt والBool-، تقوم بنسخ قيمتها عندما يتم مساواتها بمتغير آخر
    بينما متغيرات نوع المرجع (Reference type) -مثل أي اوبجكت من كلاس-، تقوم باعارة قيمتها عندما يتم مساواتها بمتغير آخر. 
    لنشرح الفرق بينهم سنطرح هذا المثال البسيط لنوع القيمة:
    var a: Int var b: Int a=5 b=a a=10 print(a) print(b) في المثال السابق، سيتم طباعة قيمتين مختلفتين لكل من a=10 و b=5، لأن قيمة a نسخت في البداية الى b حتى أصبح كل متغير يحمل قيمة خاصة ومستقلة عن المتغير الآخر، وعند تغيير قيمة a لم تتأثر قيمة b بذلك.
    ولنوع المرجع لنرى المثال التالي:
    var a = Car() var b: Car b = a a.startCar() b.printCarStatus() في المثال السابق، اذا طبقنا هذا الكود فسنلاحظ أن متغير السيارة b يعمل بالفعل، أي أن قيمة a اعيرت الى b، بحيث أي تغيير يطرأ على a سيؤثر بb، وأي تغيير يطرأ على b سيؤثر بa.
     
    اذا من المهم جدا أن نتذكر بأن الStructures من نوع القيمة (Value type)، بينما الClasses من نوع المرجع (Reference type).
     
    اختلاف آخر صغير بين الستركتشرز والكلاسات، أن الproperties في الستركتشر لا يمكن تعديلها بطريقة مباشرة من الميثودز، بل يجب استعمال كلمة mutator لكل ميثود كي نستطيع تعديل الproperties.
    مثال:
    struct Circle { var centerX = 0.0, centerY = 0.0, radius = 1.0 mutating func doubleRadius() { radius = radius * 2 } } اذا أردنا مضاعفة قيمة الradius من داخل الفنكشن doubleRadius، فسنضطر لاستخدام كلمة mutator قبل الميثود، دلالة على تغيير المتغير radius بقيمة أخرى دون الحاجة لنسخه.
     
    فيما عدا ذلك، فإن الستركتشرز تعتبر مشابهة تماما للكلاسات.
     
    ثانيا: Enumerations او enum                                                                                                                                                                    
    التعدادات (Enumerations) هي طريقة نستطيع من خلالها أن نجمع العديد من قيم المتغيرات المرتبطة ببعضها. وكما الستركتشرز، فان التعدادات تعتبر من انواع القيمة (Value type).
    لنفترض بأننا نريد أن نعرف مجموعة الكواكب الشمسية، بدون استخدام التعدادات سنقوم بكتابة كود مشابه للتالي:
    let mercury = 1 let venus = 2 let earth = 3 ... وبهذه الحالة سنضطر لاضاعة أسطر أخرى للتأكد من الادخال الصحيح، فمثلا لو أدخل احدهم الرقم -1:
    var currentPlanet = -1 // not a valid planet! فسيكون هناك خطأ أنتاء عمل البرنامج، ان لم نقم بكتابة if-statements مناسبة
    ولكن في حالة التعدادات، يمكننا كتابتها كالتالي:
    enum Planet { case mercury = 1 case venus = 2 case earth = 3 case mars = 4 case jupiter = 5 case saturn = 6 case uranus = 7 }  او اختصارا:
    enum Planet { case mercury, venus, earth, mars, jupiter, saturn, uranus, neptune } والآن، ان تم ادخال قيمة غير صحيحة:
    var currentPlanet = Planet.mercury currentPlanet = -1 // error! فسنتعرف على الخطأ مباشرة.
     
    في هذا المثال سنرى امكانية تخزين قيم مختلفة لكل case لاحقا، الآن لننشئ مجموعة الألوان الخاصة بنا:
    enum Color { case rgb(Int, Int, Int) case argb(Int, Int, Int, Int) case cmyk(Int, Int, Int, Int) case name(String) } عند كتابة الenum بهذه الطريقة، فكأننا نخبر الSwift بأن كل case ستحصل على قيم خاصة بها لاحقا، مثل:
    var blue = Color.rgb(0, 0, 255) ويمكن استعمال الاختصار التالي عند تغيير قيمة المتغير:
    var blue = Color.rgb(0, 0, 255) blue = .argb(100, 0, 0, 255) blue = .name("blue") فبعد المساواة الأولى، أصبح من المعروف أن المتغير blue لن يخرج عن أحد خيارات المتعدد Color.
     
     
    وهنا نصل الى ختام موضوعنا، تقبل الله منا ومنكم صالح الأعمال
    والسلام عليكم ورحمة الله
    مستوى المقال: متوسط

    بواسطه AMR0T , في

  • تعلمنا في ما سبق عن  نوع من  الـ Animation وهو الـ UIView.animate
    والذي يعتبر الأكثر استخداما
     
    واليوم سوف نتعلم عن نوع مختلف وهو UIView.transition
     
    قبل ان نبدأ في الدرس ، ما الفرق بينهما ؟
     
    باختصار UIView.animate مسؤول عن ملكية الـ UIView من عمل تحريك وتكبير والتفاف وغيرها
    في حين UIView.transition مسؤول عن إضافة وحذف الـ View
     
    تستطيع عند إضافة الـ View كـ Subview انك تعمل Animation في لحظة اضافته او حذفه
     
    اعلم الكلام غير مفهوم !
     
    مع التطبيق سوف تتضح الصورة .
     
    لتسهيل الامور لن اتطرق الى موضوع إضافة وحذف الـ SubView عن طريق الاكواد ولكن سوف اشرحها بطريقة اكثر بساطة .
     
    اذا لنبدأ الدرس .
     
    نقوم بإضافة Label ونجعل لون النص باللون الأبيض ولون الخلفية باللون الأسود
    ومن ثم نضيف زر

    كما في الصورة التالية :

     
    نقوم بإضافتهم الى ملف اكواد التطبيق ونجعل اسم الـ Label
    بـ Label واسم الـ Function بـ Transition
     

     
        @IBOutlet weak var Label: UILabel! @IBAction func Transition(_ sender: Any) {            }
    الان في viewDidLoad


    نضيف التالي :
     
    Label.isHidden = true
    لماذا ؟
    ذكرنا في السابق بأن الـ UIView.transition
    يعمل اثناء إضافة وحذف الـ View

    لذا في الكود السابق ما نقوم به هو حذفه من الـ View
    بجعله غير ظاهر !

     
    في الدروس السابقة استخدمنا .alpha
    فما الفرق ؟
     
    الـ .alpha هي الشفافية
    بمعنى 1 يعتبر لا توجد شفافية في حين 0.5 تعني وجود شفافية و 0 يعني انعدام الشفافية
     
    وهي من ملكيات الـ UIView.animate بصورة أخرى من المكيات التي يمكن عمل لها animate
     
    لكن الـ isHidden يزيل الـ View
    وليست من الملكيات التي تستطيع عمل لها animate
    فاذا استخدمتها بداخل اقواس UIView.animate لن يظهر أي Animation !
     
    بصورة مختصرة : استخدام UIView.transition مع الملكيات التي لا يمكن عمل لها Animation
     
     
    نعود للدرس
     
    الان نقوم بعمل التالي بداخل اقواس Transition

     
    UIView.transition(with: Label, duration: 0.5, options: .transitionCurlDown, animations: {                                      self.Label.isHidden = false                                   }, completion: nil)
    كما تلاحظ بصورة عامة فهو مشابه للـ UIView.animate

    الاختلاف with وتعني ماهو الـ view الذي تريد عمل له الـ transition
    تكتب نفس اسم الـ View وهنا نحن استخدمنا Label فنقوم بكتابة اسم الـ Label

    الـ options هناك أنواع مختلف سوف اذكرها بعد قليل
    ما اريد توضيحه هنا الانواع التي ذكرتها في موضوعي السابق .curveEaseIn واخواتها يمكنك دمجها مع الانواع الخاصة بالـ transition بعمل مربع الاريه [] والفصل بينهم بعلامة فاصلة
     
    ماقمنا بفعله داخل الاقواس هو فقط حولنا الحالة من مخفي الى ظاهر بالتغير من true الى false
     
    أنواع الـ options :

    transitionCurlDown :
    وهو النوع الذي استخدمناه في الكود السابق

     
    transitionCurlUp :
    هيا عملية معاكسه للعملية السابقة لم استطيع عمل صورة متحركة توضحها
     
    transitionFlipFromTop:


    :transitionFlipFromBottom

     
    :transitionFlipFromRight


    :transitionFlipFromLeft


    transitionCrossDissolve:


    هناك نوع أخير وهو
    .showHideTransitionViews
     
    سيتضح فائدته في الـ Function الاخر للـ transition
     
    من الامور التي اتضحت من أنواع الـ Options السابقة
    بأنك قد ترغب باستخدام الـ transition لعمل تأثير معين
    لن تستطيع عمله باستخدام الـ UIView.animate
     
    ولكن من الامور الأخرى هو عمل تأثير انتقالي وسيكون المثال التالي توضيحا للطريقة
     
     
    قبل العوده لاستكمال الدرس هنا تلميحه بسيطة وهي


    هل تريد مشاهدة التأثير ببطيء ؟


    عند تشغيل التطبيق على المحاكي
    اذهب الى خانة Debug واختار خيار Slow Animations
    ومن ثم اضغط على الزر وسظهر الـ Animation بصورة بطيئة (سلو موشن)

    كما في الصورة التالية :



     
    مثال :


    نعود للدرس 
     
     
    الان سوف ننتقل الى نوع أخرى من أنواع الـ UIView.transition
     
            UIView.transition(from: , to: , duration: , options: , completion: nil)
     كما تلاحظ في الكود السابق بأنه يطلب نوعين من الـ UIView ، وهذا النوع هو نوع انتقالي
    بحيث يعمل عملية انتقالية بين الـ View الاول الى الـ View الثاني
    بحيث يخفي الاول ويظهر الثاني !
     
    دعونا نبدأ في المثال
     
    أولا :
    نذهب الى الـ Storyboard
    ونضيف التالي :

     نضيف UIView
    ونجعله بحجم مستطيل صغير

    ومن ثم بداخله نضيف UIView اخر  ونجعله بنفس حجم الـ UIView  السابق
    ونغير لونه الى الاخضر
     
     ومن ثم نضيف Label اذا اردت
     
    وأيضا نضيف Button ، نحذف النص الذي بداخله ونجعله بحجم الـ UIView
     
    كما في الصورة التالية :


     
    ومن ثم نقوم بنسخ الـ UIView الذي قمنا بعمله في الخطوة السابقة ونغير النص ولون الـ UIView
    الى الازرق
     
    كما في الصورة التالية :




    الان اصبح لدينا ثلاثة من الـ UIView
    اثنين بداخل UIView واحد
    وفوق كل UIView زر

    بما يعني ٣ من الـ UIView
    و ٢ من الـ Button
     
    قد تتسأل لماذا اضفنا UIView وبداخله (فوقه) اضفنا اثنين من الـ UIView
    بدلا من إضافة اثنين من الـ UIView مباشرةً الى الـ  ViewController؟

    السبب لأنه عند عمل الـ transition
    سنقلب الـSuperview
    الذي سيكون الـ View الأساسي
    بمعنى سوف تنقلب كامل الصفحة !!

    لكن عند إضافة UIView وجعلنا اثنين من الـ UIView بداخله
    الذي سوف ينقلب هو الـ UIView الي اضفناه
    لأنه اصبح هو الـSuperview بالنسبة لهم
    بما يعني لن تنقلب الصفحة كامله !
    بما يعطي ايحاء بتأثير انقلاب البطاقة !
     
     
    ملاحظة :
    في الـ StoryBoard
    من يكون في اخر التسلسل يكون هو الاول (الظاهر)
    فالان اصبح الـ View 2
    هو الاول والـ View 1 هو الثاني
    يمكنك تغيير المسميات او فقط تقوم بسحب الـ View 2 وتجعله فوق View 1

    بالشكل التالي :


    ملاحظة ٢ :
    عندما يكون هناك نوعين مختلفة فوق بعض  (في المثال هذا هناك اثنين من الـ View) ، سوف يكون من الصعب مشاهدة الـ View الذي في الخلف ، اذا طبقت الملاحظة الاولى بعد عمل القيود سوف تواجه مشاكل مع القيود !

    اذا ما الحل ؟

    كل ما عليك فعله هو الضغط على الـ View الذي في المقدمة (الذي يكون الأخير في الترتيب)
    ومن ثم إزالة علامة الصح من Installed
    وعندها ستخفي وسيظهر الـ View الذي كان في الخلف وسيسهل عليك تعديله
    بعد الانتهاء من التعديلات قم بتفعيل الصح مره أخرى !

    صورة توضيحية :


    الان نقوم بإضافتهم الى ملف الاكواد
     
    سنقوم بإضافة فقط الـ UIView
    الذي باللون الأزرق والاخضر
     
    وأيضا سوف نضيف Action للزر

    ونربط الزرين بهذا الـ Action
     
    بصيغة أخرى سوف يصبح لدينا Function واحد
    وزرين مرتبطين به !
     
    لأننا نريد جعل البطاقة تنقلب مرتين عند اللمس
    عوضا عن عمل اثنين من الـ Function سوف نعمل على Function واحد فقط
     
    كما في الصورة التالية :


    وبالتالي ملف الاكواد سوف يصبح بالشكل التالي :
     
    import UIKit class ViewController: UIViewController {     @IBOutlet weak var View1: UIView!          @IBOutlet weak var View2: UIView!               override func viewDidLoad() {         super.viewDidLoad()     }          @IBAction func FlipButton(_ sender: UIButton) {     }        
     
    الان بداخل الـ FlipButton

    نقوم بكتابة التالي :

     
     @IBAction func FlipButton(_ sender: UIButton) {                  UIView.transition(from: self.View1, to: self.View2, duration: 0.5, options: [.transitionFlipFromRight , .showHideTransitionViews], completion: nil)              }
    ما قمنا به هو جعلنا الـ View1 ينقلب الى View2
    لاحظ اننا استخدمنا الـ showHideTransitionViews
    لماذا ؟

    لانه بعد عملية الانتقال سوف يتم حذف الـ View1
    من الـ Suberview
    وبالتالي سوف يسبب بخطأ nil

    والخيار هذا بدل من ازالت الـ View1 سوف يقوم بإخفائه فقط

    الان عند التشغيل سوف تلاحظ بانه ينقلب من View1 الى View2
    ومن ثم لن يعود الى View1
    بل سوف يستمر بعرض View2
     
    صورة توضيحية بالنتيجة الحالية :
     


    لماذا لم يعود الى الـ View الاول ؟

    لأنه الكود الذي كتبناه يقوم على تحويل من View1 الى View2
    بما يعني دائما سوف يظهر View2

    باستطاعتنا تعديل الخطأ
    بإضافة Boolean

     
        var check = false اسفل 
     
        @IBOutlet weak var View1: UIView!          @IBOutlet weak var View2: UIView!
     ومن ثم نغير الكود الى هذا الشكل

     
        @IBAction func FlipButton(_ sender: UIButton) {                  check = !check                  let fromView = check ? View1 : View2         let toView = check ? View2 : View1         UIView.transition(from: fromView!, to: toView!, duration: 0.5, options: [.transitionFlipFromRight , .showHideTransitionViews], completion: nil)              }
    ما الذي قمنا به هنا ؟

    قمنا بتغير حالة الـ Boolean
    اذا كان false سوف يصبح true
    والعكس صحيح
     
    ملاحظة :
    علامة التعجب هنا معناها اعكس القيمة!

    ومن ثم اضفنا متغير باسم fromView
    واضفنا شرط اذا كان true اجعله View1 اذا كان false اجعله View2

    واضفنا متغير اخر باسم toView
    واضفنا شرط اذا كان true اجعله View2 اذا كان false اجعله View1

    ومن ثم اضفنا المتغيرات الجديدة الى  from و to بداخل Function الـ UIView.transitio
     
     
    اعلم بانه البعض سوف يرى بأن طريقة كتابة الـ IF غريبة وغير منطقية بالنسبة له
     
    لذا لتبسيط الامور يمكن أيضا كتابتها بالطريقة التالية :
     
        @IBAction func FlipButton(_ sender: UIButton) {                  check = !check                  var formView : UIView                      if check == true {                formView = View1             }else {                formView = View2         }                  var toView : UIView                  if check == true {             toView = View2         }else {             toView = View1                      }                  UIView.transition(from: formView, to: toView, duration: 0.5, options: [.transitionFlipFromRight , .showHideTransitionViews], completion: nil)              }
    صورة توضيحية بالنتيجة :



     
    مستوى المقال: متوسط

    بواسطه X901 , في

  • Ads Belongs To This website

    عالم البرمجة

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