لوحة المتصدرين
المحتوى الأكثر حصولًا على سمعة جيدة
المحتوى الأعلى تقييمًا في 09/21/21 في كل الموقع
-
لقد قمت بتغيير اسم التطبيق في جانغو Django عن طريق إعادة تسمية المجلد وجمل الإستدعاء imports وجميع (القوالب templates / الفهارس indexes). لكني الآن أحصل على هذا الخطأ عندما أحاول تشغيل المشروع عن طريق الأمر التالي: python manager.py runserver الخطأ الذي يظهر كالتالي: Error: Could not import settings 'appname.settings' (Is it on sys.path?): No module named settings كيف يمكنني تصحيح هذا الخطأ وحلّه؟ أو كيف يمكنني إعادة تسميه مشروع جانغو Django؟2 نقاط
-
أحاول أن أقوم بإرسال رسالة إلى البريد الإلكتروني، لذلك قمت ببعض التعديلات في ملف settings.py الخاص بي: EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' EMAIL_HOST = 'localhost' EMAIL_PORT = 1025 EMAIL_HOST_USER = '' EMAIL_HOST_PASSWORD = '' EMAIL_USE_TLS = False وكود إرسال البريد الإلكتروني الذي لدي كالتالي: from django.core.mail import EmailMessage email = EmailMessage('my title', 'Hello, World!', to=['example@gmail.com']) email.send() بالطبع ، إذا قمت بإعداد خادم تصحيح أخطاء debugging server من خلال الأمر التالي، فيمكنني رؤية البريد الإلكتروني في الـ terminal: python -m smtpd -n -c DebuggingServer localhost: 1025 لكن كيف يمكنني إرسال البريد الإلكتروني ليس إلى خادم التصحيح ولكن إلى example@gmail.com، أي كيف يمكنني إرسال رسالة حقيقية إلى بريد إلكتروني حقيقي؟2 نقاط
-
أنا أستخدم django-rest-framework-simplejwt لتسجيل المستخدم، ومن خلال كود التالي يمكنني الحصول على refresh token و access token بدون مشكلة: class RegistrationSerializer(serializers.ModelSerializer): pwd = serializers.CharField(write_only=True) tokens = serializers.SerializerMethodField() class Meta: model = UserProfile fields = ['username', 'mail', 'pwd', 'tokens'] def get_tokens(self, user): user = UserProfile( mail=self.validated_data['mail'], username=self.validated_data['username'] ) pwd = self.validated_data['pwd'] user.set_password(pwd) tokens = RefreshToken.for_user(user) refresh = text_type(tokens) access = text_type(tokens.access_token) data = { "refresh": refresh, "access": access } return data def save(self): user = UserProfile( mail=self.validated_data['mail'], username=self.validated_data['username'] ) pwd = self.validated_data['pwd'] user.set_password(pwd) user.save() return user المشكلة هي أنه في كل مرة أقوم فيها بإنشاء مستخدم ، يمكنني الحصول على كل من refresh token و access token ، ولكن في قاعدة البيانات لا يمكنني العثور على هذه الرموز tokens. لذا أعتقد أنني لم أقم بتخزينها ، فهل يجب علي تخزين هذه الرموز في قاعدة البيانات؟ وكيف أقوم بذلك؟2 نقاط
-
أقوم أولاً بإحضار جميع المنشورات والمؤلفين من ContentfulAPI ، ثم أقوم بعمل تكرار لهم لإنشاء مسار صالح لتمريره إلى مصفوفة المسارات export const getStaticPaths = async () => { const posts = await DataController.getEntriesByContentType( "componentBlog", ); const blogPosts = posts.items.map(item => { return {params: {blog_post: [item.fields.category.replace(/\s+/g, '-').replace(/'/g, '').toLowerCase(), item.fields.slug]}} }) const authors = await DataController.getEntriesByContentType( "author", ); const authorPaths = authors.items.map(item => { return {params: {blog_post: ['author', item.fields.slug]}} }) return { paths: [ blogPosts, authorPaths, ], fallback: false, } } وقد تلقيت هذا الخطأ عندما أحاول الوصول إلى رابط مدونة error - Error: Additional keys were returned from `getStaticPaths` in page "/blog/[...blog_post]". URL Parameters intended for this dynamic route must be nested under the `params` key, i.e.: return { params: { blog_post: ... } } Keys that need to be moved: 0, 1, 2, 3, 4, 5, 6, 7, 8. at C:\Workspace\phoenix-v2\next\new-phoenix\node_modules\next\dist\build\utils.js:518:23 at Array.forEach (<anonymous>) at Object.buildStaticPaths (C:\Workspace\phoenix-v2\next\new-phoenix\node_modules\next\dist\build\utils.js:492:17) at processTicksAndRejections (internal/process/task_queues.js:95:5) { type: 'Error', page: '/blog/[...blog_post]'2 نقاط
-
لدي مشكلة في الحصول على البيانات وتعيينها في localStorage فأنا أستخدم NextJs لذا لا يمكنني استخدام localStorage في البداية. أحاول حل المشكلة باستخدام useEffect لكن لدي حلقة لا نهائية لا أعرف أفضل طريقة لحل المشكلة ، باستخدام useCallback أو useMemo أو useRef. const [ meetings, setMeetings] = useState([]) // meetings= [{meeting1},{meeting2}] useEffect(() => { if(localStorage.getItem('meetings') === undefined || localStorage.getItem('meetings') === '' || localStorage.getItem('meetings') === null ){ localStorage.setItem('meetings', JSON.stringify([])) } if( JSON.parse(localStorage.getItem('meetings')).length === 0){ const meetingsInLocalStorage = JSON.parse(localStorage.getItem('meetings')) setMeetings([...meetings, meetingsInLocalStorage]) } },[meetings])2 نقاط
-
2 نقاط
-
لقد قمت بتثبيت برنامج xampp على لينكس توزيعة اوبنتو ولكن لا اعرف كيف اقوم بتشغيله, ارجو المساعدة2 نقاط
-
أهلًا بكم في الدرس الثاني من سلسلة تعليم بوتستراب 5، سنتعلم في هذا الدرس كيف ننشئ شريط تنقّل باستخدام بوتستراب من خلال موقع بسيط جدًا وظيفته توضيح هذه الفكرة، ومن ثمّ سنعمل على دعم اللغة العربية من خلال جعل جهة الموقع من اليمين إلى اليسار. سنركّز على النقاط التالية في هذا الدرس: تجهيز البنية التحتية للمشروع معاينة الموقع ضمن خادوم تجريبي لبُّ الموضوع: شريط التنقّل في بوتستراب تعديل الموقع ليدعم الاتجاه من اليمين إلى اليسار تجهيز البنية التحتية للمشروع لنعمل على تجهيز البنية التحتية لمشروعنا الخاص ببيع الدورات التعليمية "نبيه". أنشئ مجلّدًا جديدًا في المكان الذي ترغبه وسمّه nabih. انتقل بعد ذلك إلى Visual Studio Code واختر من القائمة File الأمر Open Folder ثم انتقل إلى المجلّد الذي أنشأته توًّا ثم اختر Select Folder لفتحه. أصبحت الآن جاهزًا للبدء بإضافة ملفات المشروع. ستلاحظ في الجهة اليسرى من نافذة Visual Studio ظهور المجلّد الذي اخترناه قبل قليل مع توفّر إمكانية إضافة ملفات أو مجلّدات أخرى إليه كما في الشكل التالي: أضف الملف index.html الذي سيمثّل ملف الواجهة الرئيسية في موقعنا. أضف أيضًا المجلدين التاليين: css الخاص بملفات التنسيق و images المجلّد الذي سنضع فيه الصور المستخدمة بالموقع (سنحتاج إليه في دروس لاحقة). أضف أيضًا الملف styles.css ضمن المجلّد css. سيكون هذا الملف في درسنا هذا فارغًا، ولكن سنعمل على استخدامه في دروس لاحقة. ستحصل في النهاية على شكل شبيه بالتالي: افتح الملف index.html بالنقر المزدوج عليه ثم انسخ الكود التالي إليه: <!doctype html> <html lang="en"> <head> <!-- Required meta tags --> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- Bootstrap CSS --> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous"> <title>السلام على الجميع!</title> </head> <body> <h1>Hello, world!</h1> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script> </body> </html> احفظ التغييرات الأخيرة. وبهذا يصبح الملف index.html جاهزًا للمعاينة. معاينة الموقع ضمن خادوم تجريبي إذا كنت تذكر في المقال الأول من هذه السلسلة، فقد أضفنا الإضافة Live Server إلى Visual Studio Code. سنستخدم هذه الإضافة الآن لمعاينة الصفحة index.html ضمن المتصفّح الإفتراضي. انقر بزر الفأرة الأيمن على الملف index.html ثم اختر الأمر Open with Live Server. سيؤدي ذلك إلى فتح نافذة أو لسان من المتصفّح الافتراضي على حاسوبك، وسترى الآن الصفحة index.html وقد ظهرت محتوياتها ضمن نافذة المتصفّح. ستحصل على شكل شبيه بما يلي: يعد هذا مؤشرًا على أنّ الأمور تجري على ما يرام. لاحظ العنوان الظاهر في شريط العنوان في نافذة المتصفّح من الشكل السابق: 127.0.0.1:5501 العنوان 127.0.0.1 هو عنوان IP للجهاز المحلّي. أمّا المنفذ 5501 فهو المنفذ الذي تُصغي فيه الإضافة Live Server للطلبات الواردة من المتصفح، يمكن بطبيعة الحال أن يختلف هذا الرقم على حاسوبك. شريط التنقل في بوتستراب تمتلك معظم المواقع على الإنترنت شريطًا رئيسيًا يتموضع عادةً في الجزء العلوي من الصفحة. يحتوي هذا الشريط على روابط تساعد في التنقّل السريع بين أجزاء الموقع. من الممكن أن تكون بعض هذه الروابط على شكل أزرار. يمكن أن يؤدي النقر على بعض هذه الأزرار إلى ظهور قائمة منسدلة مثلًا تحتوي على أوامر أخرى. كما ويمكن أن يحتوي هذا الشريط على مربع نص يسمح للمستخدمين بالبحث ضمن الموقع، وغيرها من المتطلّبات الأخرى. يدعم بوتستراب شريط القائمة هذا بصورة ممتازة. فعند ضبط بعض أصناف التنسيق القليلة ستحصل على شريط تنقّل عصري يلبّي احتياجاتك المتنوّعة. شريط تنقل بسيط لنبدأ بتشكيل شريط تنقّل بسيط. الكود التالي هو نسخة معدّلة عن الكود الموجود في صفحة التوثيق الخاصة الخاصة بشريط التنقّل في بوتستراب. انسخ الكود التالي إلى الملف index.html وضعه مكان العنصر <h1> الذي يحتوي على رسالة الترحيب التي رأيناها في الفقرة السابقة: <nav class="navbar navbar-expand-lg navbar-light bg-light"> <div class="container-fluid"> <a class="navbar-brand" href="#">نبيه</a> <ul class="navbar-nav me-auto"> <li class="nav-item"> <a class="nav-link active" aria-current="page" href="#">رابط فعال</a> </li> <li class="nav-item"> <a class="nav-link" href="#">عادي1</a> </li> <li class="nav-item"> <a class="nav-link" href="#">عادي2</a> </li> <li class="nav-item"> <a class="nav-link disabled" href="#" tabindex="-1" aria-disabled="true">غير فعال</a> </li> </ul> </div> </nav> غيّر أيضًا عنوان الصفحة (ضمن الوسم title) ليصبح "دورات نبيه". بعد حفظ التغييرات ستحصل على الشكل التالي في المتصفح (إذا لم تظهر التغييرات فورًا، يمكنك تحديث الصفحة ضمن المتصفّح): شرح الكود السابق سنتحدّث بشيء من الإسهاب عن الكود السابق كونه أساسي في بناء أشرطة التنقّل في بوتستراب. إذا نظرت إلى الكود السابق سترى أنّ العنصر الأساسي المستخدم هنا هو nav وهو عنصر HTML يُستخدم عادةً عندما نريد بناء شريط تنقل في صفحات الويب. يمكن أيضًا استخدام عنصر div عادي بدلًا من العنصر nav، ولكن عندها سنحتاج إلى بعض التعديلات الطفيفة. لذلك سنبقي على العنصر nav. لاحظ أيضًا أصناف التنسيق المستخدمة مع العنصر nav التي تأتي مع بوتستراب: navbar navbar-expand-lg navbar-light bg-light سنتحدّث هنا قليلًا عن هذه الأصناف الأربعة: الصنف navbar فهو يمنح العنصر nav هيئة شريط التنقّل مباشرةً. حيث يصبح متجاوبًا مع قياسات الشاشات المختلفة، ويقبل احتواء العناصر المفيدة الأخرى مثل العلامة التجارية branding الخاصة بالموقع، وروابط التنقّل، وإمكانية ضم الأزرار ضمن قائمة مطوية واحدة تفتح بزر collapsing للحد من عرض الشريط في حال الشاشات الصغيرة كما سنرى ذلك فيما بعد. يحتاج الصنف navbar كي يعمل بطريقة صحيحة إلى الصنف navbar-expand-lg وأخواته navbar-expand-{-sm|-md|-lg|-xl|-xxl} . ووظيفة هذه الأصناف هي السماح بنشر محتويات شريط التنقّل بشكل أفقي. جرب أن تزيل هذا الصنف، لتجد أنّ محتويات شريط التنقّل قد أصبحت مكدّسة عموديًا. بالنسبة للصنف navbar-light فهو يتحكم بالنمط theme يوجد ثلاثة أنماط رئيسية في بوتستراب هي: النمط الفاتح navbar-light والنمط الغامق navbar-dark والنمط الرئيسي navbar-primary. تتحكم هذه الأصناف بلون الخط للعناصر الموجودة ضمن شريط التنقّل nav. تعمل الأصناف الثلاثة السابقة مع الصنف الذي يتحكم بلون الخلفية لشريط التنقّل وهو عبارة عن مجموعة من الأصناف مثل: bg-light و bg-dark و bg-primary و bg-success و bg-warning. لكي تحصل على أفضل النتائج استخدم الصنف bg-light مع الصنف navbar-light والصنف bg-dark مع الصنف navbar-dark. الحرفان bg من الصنف bg-light أو الصنف bg-dark أو غيرهما، يعبّران عن الكلمة background أي الخلفية. يجعل الصنف bg-light خلفية شريط التنقّل ذا لون فاتح. كما أنّ الصنف bg-dark يجعل الخلفية تبدو غامقة، وهكذا. بالنسبة للأصناف الباقية، جرّب استخدام مزيج من أصناف التنسيق مع أصناف الخلفية لكي تختار منها ما يناسبك. جرب مثلًا النمط الغامق navbar-dark مع bg-success وهكذا. يدعم شريط التنقّل في بوتستراب (ومحتوياته أيضًا) الشكل المرن أو المتدفق Fluid في التصميم. بمعنى أنّ شريط التنقّل ينتشر أفقيًا ليحاول تعبئة عرض الشاشة المتاح. يمكن استخدام أي حاوية Container تراها مناسبة للتحكّم في مدى الانتشار الأفقي. هذا ما يبرّر استخدامنا لعنصر div مع الصنفcontainer-fluid الموجود ضمن العنصر nav مباشرةً (انظر الكود السابق). في هذه الحالة استخدمنا هذه الحاوية لضبط الانتشار الأفقي لمحتويات شريط التنقّل. على العموم يمكننا استخدام نفس التقنية تمامًا مع العنصر nav نفسه. سنتحدث عن الحاويات لاحقًا في هذه السلسلة. ولكن إذا أردت معرفة فائدة وجود هذه الحاوية. أزل صنف التنسيق container-fluid من عنصر div الذي يأتي ضمن العنصر nav مباشرةً لترى كيف يؤثّر وجودها على محتويات شريط التنقّل. سنضع ضمن عنصر div (الذي يحوي الصنف container-fluid) محتويات شريط التنقّل. والتي تنحصر في مثالنا هذا على اسم الموقع، بالإضافة إلى أربعة عناصر توضّح أنواع الروابط التي يمكن وضعها ضمن شريط التنقّل. قطعة الكود التالية موجودة ضمن عنصر div ذا الصنف container-fluid من الكود السابق: <a class="navbar-brand" href="#">نبيه</a> <ul class="navbar-nav me-auto"> <li class="nav-item"> <a class="nav-link active" aria-current="page" href="#">رابط فعال</a> </li> <li class="nav-item"> <a class="nav-link" href="#">عادي1</a> </li> <li class="nav-item"> <a class="nav-link" href="#">عادي2</a> </li> <li class="nav-item"> <a class="nav-link disabled" href="#" tabindex="-1" aria-disabled="true">غير فعال</a> </li> </ul> نضع عادةً اسم الموقع ضمن عنصر الارتباط التشعبي a. سيكون لهذا العنصر التنسيق navbar-brand ليُنسّق على شكل علامة تجارية أو أيقونة واضحة للموقع. يمكن بالطبع إضافة صورة لاسم الموقع بإضافة عنصر صورة كما سنرى فيما بعد. بعد عنصر الارتباط التشعبي وضعنا عنصر القائمة غير المرتبة ul وهي التي ستحوي الروابط الرئيسية على شريط التنقّل. لاحظ كيف وضعنا الصنف navbar-nav لهذه القائمة كي تنسجم مع شريط التنقل الموضوعة ضمنه. ولاحظ أيضًا وجود صنف آخر هو me-auto. أول حرفين من اسم هذا الصنف يشيران إلى الكلمتين margin end، وتعنيان الهامش من النهاية. مع الكلمة -auto يعني ذلك أنّنا سنجعل الهامش من الطرف النهائي تلقائي أي أنّه سيأخد أكبر هامش ممكن من الطرف النهائي، وهذا ما سيجعل عنصر القائمة يُزاح كاملًا نحو اليسار (نحو البداية) بجوار اسم الموقع (جرب إزالة هذا الصنف وانظر ماذا سيحدث). قد تتسائل عن سبب استخدام تعبير "الهامش من النهاية" في حين أنّه كان من الممكن استخدام التعبير "الهامش من اليمين" فحسب! الجواب على ذلك بسيط. باستخدام هذا التعبير الرائع نستطيع إكساب موقعنا قابلية الاتجاه من اليمين إلى اليسار بكل بساطة. فعندما يكون اتجاه موقعنا من اليسار إلى اليمين تكون البداية من اليسار والنهاية من اليمين أمًا عندما يكون اتجاه موقعنا من اليمين إلى اليسار يحدث العكس! بمعنى آخر أنّه يمكن تعديل اتجاه موقعنا البسيط كاملًا ليصبح من اليمين إلى اليسار (بدلًا من الوضع الحالي) وذلك بتعديل بسيط جدًا في الموقع كما سنرى ذلك بعد قليل. قبل الإصدار 5 من بوتستراب، كان من الممكن الوصول إلى نفس النتيجة من خلال استخدام الصنف mr-auto وهو اختصار للكلمات: margin right auto، وتعني أنّ الهامش من الطرف الأيمن سيكون تلقائي. من الواضح أنّ هذا الصنف مفيد عندما عندما يكون اتجاه الصفحة من اليسار إلى اليمين. ولكن عندما يكون اتجاه الصفحة من اليمين إلى اليسار، سيكون استخدام هذا الصنف غير مناسب كما هو واضح. هذا ما كان يجبر المطورين على إنشاء قالبين منفصلين لصفحات الموقع في حال كان هناك حاجة لدعم لغتين باتجاهين مختلفين (مثل اللغة العربية، واللغة الانجليزية). وصلنا الآن إلى عناصر القائمة li. في الحقيقة هي عناصر بسيطة يحمل كل منها الصنف nav-item، ويحوي كل منها عنصر ارتباط تشعبي a. ولكل عنصر ارتباط تشعبي منها الصنف nav-link. العنصر الأوّل الذي يحوي النص "رابط فعال" سيكون له بالإضافة للصنف nav-link الصنف active للإشارة إلى أنّ الرابط الحالي يُشير إلى الصفحة الحالية التي تُعرض أمام المستخدم. وهذا أمر مفيد كما هو واضح. أمّا العنصران الثاني والثالث اللذان يحملان النص "عادي1" و "عادي2" على الترتيب فهما عنصران عاديان افتراضيان على شريط التنقّل. أمّا العنصر الأخير: "غير فعّال" فقد نحتاج أحيانًا إلى جعل أحد الارتباطات على شريط التنقّل غير فعّالة، وهذا يمكن الحصول عليه بتطبيق الصنف disabled كما هو واضح. هذا كل شيء! في الفقرة التالية سنحوّل الموقع السابق إلى الاتجاه الذي يناسب اللغة العربية. تعديل الموقع ليدعم الاتجاه من اليمين إلى اليسار بقي علينا إضافة بعض اللمسات الأخيرة لكي نُكسب الموقع الاتجاه المناسب لدعم اللغة العربية. في البداية أود أن أشير إلى أنّ ميزة الاتجاه من اليمين إلى اليسار RTL هي ميزة تجريبية في بوتستراب حتى وقت كتابة هذا المقال. ولكن ذلك لا يمنع بالطبع من استخدامها لأنّه من المتوقّع في الفترة القريبة القادمة أن تصبح نهائية بعد التأكّد من استقرارها. نحتاج لاستخدام الاتجاه من اليمين إلى اليسار RTL إلى إجراء ثلاثة تعديلات بسيطة ضمن الملف index.html: 1- استبدال القيمة ar بالقيمة en للسمة lang ضمن الوسم html. 2- إضافة سمة جديدة للوسم html وهي السمة dir وهي مسؤولة عن تحديد اتجاه الصفحة. سنسند القيمة rtl لها. 3- استبدال العنصر التالي بالعنصر link المسؤول عن استيراد مكتبة التنسيق الخاصة ببوتستراب: <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.rtl.min.css" integrity="sha384-gXt9imSW0VcJVHezoNQsP+TNrjYXoGcrqBZJpry9zJt8PCQjobwmhMGaDHTASo9N" crossorigin="anonymous"> هذه نسخة من مكتبة بوتستراب التي تدعم (لاحظ اسمها bootstrap.rtl.min.css). يجب أن يكون الكود النهائي الموجود ضمن الملف index.html مماثلًا لما يلي: <!doctype html> <html lang="ar" dir="rtl"> <head> <!-- Required meta tags --> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- Bootstrap CSS --> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.rtl.min.css" integrity="sha384-gXt9imSW0VcJVHezoNQsP+TNrjYXoGcrqBZJpry9zJt8PCQjobwmhMGaDHTASo9N" crossorigin="anonymous"> <link href="/css/styles.css" rel="stylesheet" /> <title>دورات نبيه</title> </head> <body> <nav class="navbar navbar-expand-lg navbar-light bg-light"> <div class="container-fluid"> <a class="navbar-brand" href="#">نبيه</a> <ul class="navbar-nav me-auto"> <li class="nav-item"> <a class="nav-link active" aria-current="page" href="#">رابط فعال</a> </li> <li class="nav-item"> <a class="nav-link" href="#">عادي1</a> </li> <li class="nav-item"> <a class="nav-link" href="#">عادي2</a> </li> <li class="nav-item"> <a class="nav-link disabled" href="#" tabindex="-1" aria-disabled="true">غير فعال</a> </li> </ul> </div> </nav> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script> </body> </html> عاين الملف index.html باستخدام الإضافة Live Server لتحصل على شكل شبيه بما يلي: لاحظ أنّنا لم نمس كود HTML مطلقًا. وذلك بسبب استخدمنا لأصناف تنسيقية تصلح للاستخدام في طريقتي العرض يمين إلى يسار RTL أو يسار إلى يمين LTR. ففي حالتنا هذه استخدمنا الصنف me-auto المسؤول عن سلوك الهامش من النهاية، والذي أصبح في هذه الحالة من جهة اليسار بدلًا من جهة اليمين كما في الفقرة السابقة. يمكنك تنزيل شيفرة المقال من الملف hsoub-bootstrap5-ch02.zip. خاتمة أرجو أن تكون قد استمتعت بهذا الدرس! لقد تعلّمنا الكثير في هذا الدرس حول شريط التنقّل في بوتستراب. حيث بنينا شريط تنقّل بسيط، وأسهبنا في الشرح حول أجزاء هذا الشريط، وكيفية الإستفادة من التقنيات الجديدة في بوتستراب 5 لتحويل اتجاه الصفحة لتصبح من اليمين إلى اليسار. وفي الدرس التالي سنتحدّث عن بنية صفحة الويب باستخدام بوتستراب. اقرأ أيضًا 10 أخطاء شائعة عند استخدام إطار العمل Bootstrap بناء قائمة شجرية باستخدام البوتستراب تصميم صفحة موقع باستخدام 3 Bootstrap - الجزء الأول1 نقطة
-
مرحبًا بك في الدرس الثالث من سلسلة تعليم بوتستراب 5. سنتعرّف في هذا الدرس على مخطط الشبكة Grid Layout وهو المخطط المعتمد في بوتستراب. سنمر على النقاط التالية في هذا الدرس: الحاوية Container. مخطط الشبكة Grid. استخدام الأعمدة بطريقة متجاوبة. هذا الدرس مهم وأساسي في التعرّف على بوتستراب وكيف يعمل. الحاوية Container تُعَد الحاوية حجرة البناء الأساسية في بوتستراب، وهي عبارة عن عنصر div يحمل التنسيق container أو أخواته، وذلك لكي يكسب هذا العنصر بعض التنسيقات المسبقة والمفيدة مما يسمح باحتواء بقية العناصر ضمن الشاشة المطلوبة بيسر وسهولة. يُعتبر استخدام الحاوية ضروريًا مع مخطط الشبكة ضمن بوتستراب كما سنرى بعد قليل. يوجد ثلاثة أنواع من الحاويات في بوتستراب وهي: الحاوية العادية: عبارة عن عنصر div يحمل صنف التنسيق container. الحاوية الإنسيابية: وهي عنصر div يحمل الصنف التنسيقي container-fluid ويكون عرض هذه الحاوية هو العرض الكامل للشاشة أي 100% الحاويات ذات العرض المخصص: وهي عبارة عن خمس حاويات: container-sm و container-md و container-lg و container-xl و container-xxl ومعناها على الترتيب: الحاوية ذات العرض الصغير، وذات العرض المتوسط، وذات العرض الكبير، وذات العرض الأكبر، وذات العرض الكبير جدًا. الأمر المميز في حاويات العرض المخصّص هو أنّ الصفة المرتبطة معها (صفة العرض) لا تُفعّل إلّا إذا وصل عرض الحاوية إلى عرض أصغري يمكنك أن تدعوه عتبة الاستجابة Break Point. لكي نفهم الموضوع على أكمل وجه، أنشئ ملفًا جديدًا ضمن مجلّد العمل nabih سمّ الملف test-container.html وانسخ الكود التالي إليه مع ملاحظة أنّ التنسيقات التي تحتوي على background-color وضعتها فقط لتمييز الحاويات عن بعضها وليس لها أي دور آخر: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>اختبار الحاويات</title> <meta name="description" content=""> <meta name="viewport" content="width=device-width, initial-scale=1"> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous"> </head> <body> <div class="container" style="background-color: royalblue;">حاوية عادية</div> <div class="container-sm" style="background-color:sandybrown;">عرض مئة بالمئة حتى عتبة العرض الصغير</div> <div class="container-md" style="background-color: salmon;">عرض مئة بالمئة حتى عتبة العرض المتوسط</div> <div class="container-lg" style="background-color: lightpink;">عرض مئة بالمئة حتى عتبة العرض الكبير</div> <div class="container-xl" style="background-color: lightgreen;">عرض مئة بالمئة حتى عتبة العرض الأكبر</div> <div class="container-xxl" style="background-color: lightsteelblue;">عرض مئة بالمئة حتى عتبة العرض الكبير جدًا</div> <div class="container-fluid" style="background-color: lightpink;">حاوية انسيابية</div> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script> </body> </html> احفظ التغييرات ثم انقر بزر الفأرة الأيمن على هذا الملف، واختر تشغيله عن طريق الإضافة Live Server. ستظهر محتويات الملف ضمن المتصفح. جرّب الآن تصغير عرض نافذة المتصفّح إلى أصغر حد ممكن، ستلاحظ أنّ جميع الحاويات قد شغلت العرض الأعظمي الممكن 100%كما في الشكل التالي وذلك بسبب أنّ العرض الحالي هو صغير جدًا ولم يصل بعد إلى عتبة الإستجابة الأولى "صغير" : ابدأ الآن بالسحب وتوسيع عرض النافذة تدريجيًا. ستلاحظ أنّ الحاويتان العادية وذات العرض الصغير قد أخذتا منحًا مغايرًا عن باقي الحاويات الأخرى. كما في الشكل التالي: وسبب ذلك أنّ الحاوية العادية يكون عرضها دومًا مساويًا لقيمة الثابت max-width والذي تتغيّر قيمته وفقًا لاستعلامات Media Queries. أمّا الحاوية ذات العرض الصغير فقد بلغت عتبة الاستجابة الخاصة بها عندما بدأت بتوسيع عرض النافذة، وبالتالي سيصبح عرضها مساويًا أيضًا لقيمة الثابت max-width. إذا تابعت توسيع عرض النافذة بنفس الأسلوب، ستلاحظ أنّه عندما تبلغ كل عتبة ستنضم إحدى الحاويات إلى رفيقاتها السابقة في اكتساب العرض max-width حتى إذا ما وصل عرض النافذة لأقصى حد ممكن (على اعتبار أنّك تستخدم شاشة حاسوب عادية) ستحصل على شكل شبيه بما يلي: لاحظ أنّ الحاوية الإنسيابية container-fluid بقي عرضها ثابتًا بحيث يأخذ عرض الشاشة كاملًا 100%. يلخص الجدول التالي عتبات الإستجابة (قيم max-width) لكل من الحاويات السابقة: table { width: 100%; } thead { vertical-align: middle; text-align: center; } td, th { border: 1px solid #dddddd; text-align: right; padding: 8px; text-align: inherit; } tr:nth-child(even) { background-color: #dddddd; } صغير جدا - أصغر من 576 بيكسل صغير - أكبر من أو يساوي 576 بيكسل متوسط - أكبر من أو يساوي 768 بيكسل كبير- أكبر من أو يساوي 992 بيكسل الأكبر - أكبر من أو يساوي 1200 بيكسل كبير جدًا - أكبر من أو يساوي 1400 بيكسل .container 100% 540px 720px 960px 1140px 1320px .container-sm 100% 540px 720px 960px 1140px 1320px .container-md 100% 100% 720px 960px 1140px 1320px .container-lg 100% 100% 100% 960px 1140px 1320px .container-xl 100% 100% 100% 100% 1140px 1320px .container-xxl 100% 100% 100% 100% 100% 1320px .container-fluid 100% 100% 100% 100% 100% 100% يمكنك الآن التخلص من الملف test-container.html من مجلّد المشروع إن أحببت. مخطط الشبكة Grid يمكنك أن تبني باستخدام مخطط الشبكة في بوتستراب واجهات بمختلف الأشكال والأحجام. يعتمد مخطط الشبكة على مفهوم صندوق التخطيط المرن Flex Box في بناء الواجهات، وهو يستخدم، كما سنرى بعد قليل، مزيج من الحاويات والأسطر والأعمدة لتحقيق هذا الهدف. يدعم مخطط الشبكة ست عتبات استجابة بنفس مبدأ عتبات الإستجابة التي مرّت معنا في فقرة الحاويات، وهي: sm و md و lg و xl و xxl، أمّا السادس فهو للقياس: "صغير جدًا" (أقل من 576 بيكسل) وفعليًا ليس له اختصار محدّد. يتكوّن مخطّط الشبكة من 12 عمود. تكون الأعمدة محدّدة ضمن أسطر وذلك للتحكم بعدد الأعمدة الموجودة بكل سطر على حدة. في أي سطر، يتوزّع العرض المُتاح بالتساوي على الأعمدة المتماثلة الموجودة ضمنه. انظر إلى المثال الأساسي التالي الذي يوضّح بنية بسيطة جدًا لاستخدام مخطط الشبكة: <div class="container"> <div class="row"> <div class="col" style="background-color: lightgreen;"> Row 1 - Col 1 </div> <div class="col" style="background-color: lightpink;"> Row 1 - Col 2 </div> </div> <div class="row"> <div class="col" style="background-color: lightsalmon;"> Row 1 - Col 1 </div> <div class="col" style="background-color: lightblue;"> Row 2 - Col 2 </div> <div class="col" style="background-color: lightseagreen;"> Row 3 - Col 3 </div> </div> </div> لاحظ في البداية وجود حاوية وهي ضرورية لكي يعمل مخطط الشبكة. بعد ذلك نبدأ بتعريف الأسطر باستخدام عنصر div مع الصنف التنسيقي row. في الكود السابق عرّفنا سطرين. يحتوي السطر الأوّل على عمودين. نعرّف أي عمود باستخدام العنصر div مع الصنف التنسيقي col (أو أخواته كما سنرى بعد قليل) أمّا السطر الثاني فيحتوي على ثلاثة أعمدة كما هو واضح. النصوص التي تراها في الكود السابق مثل: "Row 1 - Col 1" هي نصوص توضيحية، أيضًا هنا، جميع تنسيقات background-color هي فقط لتوضيح البنية الناتجة وليس لها أي دور في مخطّط الشبكة. لاختبار الكود السابق بسرعة يمكن تجريبه مباشرة على موقع مثل codeply.com. يمكنك فيه تجريب الكود بلا تسجيل مسبق. اختر Bootstrap 5 من القائمة الجانبية اليسرى ليظهر مختبر جاهز لتجريب الكود. احذف جميع الكود التلقائي الموجود مسبقًا في قسم HTML الموجود في الناحية اليسرى، وانسخ الكود السابق إليه ضمن هذه المنطقة. بعد ذلك ستلاحظ وجود أيقونة صغيرة أعلى الصفحة تحمل ما يشبه زر تشغيل، انقرها لترى النتائج في الأسفل. ستحصل على شكل شبيه بما يلي: يمكنك استخدام هذا الموقع دومًا في حال أردت تجريب ميزة جديدة بسرعة. كما أوضحنا توًا لدينا 12 عمود ضمن مخطّط الشبكة لكل منها العرض نفسه. ولكن في بعض الأحيان قد نحتاج إلى أن يكون أحد الأعمدة أعرض من باقي الأعمدة الأخرى، أو أن تحتاج أن يكون للأعمدة ضمن سطر ما عرض مختلف لكل منها. في الحقيقة يدعم مخطّط الشبكة هذا الأمر بصورة جميلة. لكي نفهم هذا الأمر تمامًا، تخيّل أنّ العرض المتاح ضمن الحاوية مقسّم إلى 12 حصّة متساوية فيما بينها. عندها يسمح بوتستراب بتخصيص أي عدد من هذه الحصص لأي عمود. لنفرض مثًلا أنّه يوجد لدينا ثلاثة أعمدة ضمن أحد الأسطر. يمكننا مثلًا تخصيص حصتين للعمود الأول وأربع حصص للعمود الثاني ونترك العمود الثالث في الحالة الافتراضية، أي بدون تعيين أي حصة له. أي كما في الكود التالي: <div class="container"> <div class="row"> <div class="col-2" style="background-color: lightgreen;"> Row 1 - Col 1 </div> <div class="col-4" style="background-color: lightpink;"> Row 1 - Col 2 </div> <div class="col" style="background-color: lightblue;"> Row 1 - Col 3 </div> </div> </div> لاحظ كيف عيّنت الحصص من خلال الأرقام الموجودة بجوار الصنف التنسيقي col، فالعمود الأول أصبح له الصنف التنسيقي col-2 أمّا العمود الثاني فأصبح له الصنف التنسيقي col-4 أمّا العمود الثالث فله الصنف التنسيقي col فقط بدون أي تخصيص للحصص. جرّب الكود السابق في codeply لتحصل على شكل شبيه بما يلي: لاحظ كيف أنّ عرض العمود الثاني هو ضعف العمود الأوّل وهذا أمر منطقي بالطبع، ولاحظ أيضًا أنّ العمود الثالث الذي لم نخصص له أي حصة قد شغل باقي الحصص المتاحة وهي في حالتنا هذه 6 حصص (تذكر حصة العمود الأول + حصة العمود الثاني = 6). إذًا، عندما لا نحدّد أي حصة للعمود فإنّه يشغل دومًا باقي الحصص المتاحة. ولو فرضنا وجود عمود رابع لم نحدد له أيضًا أي حصة (مثل العمود الثالث) فإنّه سيتقاسم باقي الحصص المتاحة الباقية مع العمود الثالث (سيأخذ كل واحد منها 3 حصص) وهكذا. ولا يهم بالطبع فيما إذا كان مثل هذين العمودين (أو أكثر) متجاورين أم متفرقين ضمن بقية الأعمدة الأخرى في حال وجودها. من الواضح بحسب السيناريو السابق أنّ عدد الأعمدة التي يمكننا إنشاؤها ضمن مخطّط الشبكة هي 12 عمود على الأكثر. وإذا نظرنا إلى هذا الأمر من زاوية أخرى، فيجب أن يكون مجموعة الحصص دومًا يساوي 12 حصة. استخدام الأعمدة بطريقة متجاوبة كما رأينا في الفقرة السابقة يمكننا إنشاء حتى 12 عمود ضمن مخطط الشبكة، ولكن المشكلة أنّ هذه الأعمدة ستسلك نفس السلوك عبر جميع الشاشات الممكنة. بمعنى آخر لا يمكننا بحسب المعلومات التي حصلنا عليها في الفقرة السابقة أن نغيّر مثلًا عرض أي عمود إذا تغيرت الشاشة الحالية من شاشة جوال إلى شاشة حاسوب كبيرة وهذا أمر مرغوب جدًا. ففي الحالة العامة يمكن لأي موقع أن يُعرض على شاشة حاسوب عادي، أو على شاشة جوال، ومن المفترض أن يتغير شكل الموقع بشكل يتناسب مع حجم الشاشة التي يُعرض ضمنها لكي يُعتبر هذا الموقع متجاوبًا. في الحقيقة يوجد حل أنيق يوفره لنا بوتستراب يتمثّل في إضافة بسيطة بجوار رقم الحصة التي ننوي تخصيصها للعمود وذلك على الشكل التالي: col-{sm|md|lg|xl|xxl}-n فمثًلا يمكننا أن نخبر أحد الأعمدة أننا نرغب بأن يأخذ 6 حصص في حال كانت الشاشة متوسطة العرض أو أكثر عندها نكتب col-md-6. في هذه الحالة سيأخذ العمود نصف العرض المتاح للشاشة إذا كان قياسها متوسط أو أعلى. أمّا إذا كان قياس الشاشة أقل من متوسط فإنّه سيأخذ العرض الكامل المتاح للشاشة (إذا كان العمود موجود لوحده ضمن السطر) لأننا لم نخبر العمود كيف يتصرف في حال كانت الشاشة أصغر من القياس المتوسط. يمكننا أيضًا الدمج بين أكثر من صنف تنسيقي لكي نُكسب العمود سلوكًا مختلفًا من أجل قياسات مختلفة للشاشة. انظر مثلًا إلى العمود التالي: <div class="col-6 col-md-4"></div> سيأخذ العمود السابق نصف العرض المتاح لأي شاشة يكون قياسها أقل من المتوسط بسبب وجود الصنف التنسيقي col-6. أمّا عندما يبلغ قياس الشاشة متوسط أو أكثر فعندها سيأخذ العمود أربع حصص فقط من عرض الشاشة بسبب وجود الصنف التنسيقي col-md-4. يمكن إضافة أي عدد من الأصناف التنسيقية التي تضبط عرض العمود من أجل كل قياس من القياسات الخمسة الرئيسية التي تعرفنا عليها في هذا الدرس. لنأخذ الآن مثال أكبر قليلًا يحتوي على عدة أسطر وأعمدة لكي نتأكّد من أنّنا قد استوعبنا الفكرة جيّدًا. انظر إلى الكود التالي: <div class="container"> <!-- الموضع 1 --> <div class="row"> <div class="col-md-8">.col-md-8</div> <div class="col-6 col-md-4">.col-6 .col-md-4</div> </div> <!-- الموضع 2--> <div class="row"> <div class="col-6 col-md-4">.col-6 .col-md-4</div> <div class="col-6 col-md-4">.col-6 .col-md-4</div> <div class="col-6 col-md-4">.col-6 .col-md-4</div> </div> <!-- ستأخذ الأعمدة في هذا السطر 50% من العرض الكلي المتاح بصرف النظر عن نوع الشاشة --> <div class="row"> <div class="col-6">.col-6</div> <div class="col-6">.col-6</div> </div> </div> انظر إلى الموضع 1 ضمن الكود السابق. في الشاشات الصغيرة ستتكدّس الأعمدة في هذا السطر فوق بعضها بحيث يحتل العمود الأول العرض الكلي والعمود الثاني نصف العرض الكلي. أمّا في الكود الذي يلي الموضع 2، فيشير إلى أنّه في الشاشات الصغيرة سيحتل كل عمود 50% من العرض الكلي. أمّا في الشاشات المتوسطة فأكبر، سيأخذ كل عمود ثلث العرض الكلي المتاح. بادر فورًا إلى تجربته ضمن Visual Studio Code (وليس ضمن codeply.com لكي تحصل على تجربة أدق). صغّر نافذة المتصفّح وكبّرها ولاحظ ماذا يحدث للأعمدة. يمكنك بالطبع إضافة تنسيقات لونية باستخدام background-color لكي تلاحظ التغييرات. ستحصل في حالة الشاشة الكبيرة على شكل شبيه بما يلي: يمكنك أيضًا استخدام أدوات المطوّر التي توفّر تجربة جيدة للمطورين في تجربة واختبار تطبيقات الويب الخاصة بهم. يمكنك قراءة المزيد حول هذا الموضوع من هنا. خاتمة نكون بهذا قد وصلنا إلى نهاية هذا الفصل المهم الذي سنبقى نستقي من المعلومات الواردة فيه حتى نهاية هذه السلسلة. سنعمل في الدرس التالي على تطبيق المفاهيم الواردة في هذا الدرس ضمن موقعنا الذي نبنيه تدريجيًا "نبيه"، وسنعمل في الدرس القادم على تحديث مشروعنا "نبيه" بالمعلومات الواردة في هذا الدرس بالإضافة إلى المعلومات التي سنحصل عليها في الدرس القادم. اقرأ أيضًا شريط التنقل في بوتستراب 5 مدخل إلى إطار العمل بوتستراب 5 10 أخطاء شائعة عند استخدام إطار العمل Bootstrap1 نقطة
-
1 نقطة
-
اذا أردت أن أتعلم لغة C كمدخل للبرمجة وطبقت عليها تمارين وتطبيقات ثم بعد ذلك اتعلمت دورة حسوب php , هل هذا المسار سوف يجعلني backend ممتاز وهل يجب أن أتعلم الخوارزميات والداتا ستركتشر؟1 نقطة
-
السلام عليكم لو عندى view وهى مستقيمة كيف اجعلها نائمة بدون ان اغير flexDirection ل container الخاص بها مثلا <View style={{ hight: 50, width:20, backgroundColor:"red" }} /> كودى هذا ينتج عنه view لونها احمر مستقيمة .. انا اريد انا اجعلها نائمة بدون ان اغير ال hight و width .. هل يمكن فعلها ب react native ؟1 نقطة
-
مرحبا اخوتي ماالفرق بين الذواكر المشتركة UMA والذواكر المشتركة من نوع NUMA1 نقطة
-
لقد قمت بإعداد ملف تكوين webpack 5 بسيط مع خادم مطور يبدو أنه يعمل ولكن عندما أقوم بإضافة <link href="/style.css" rel="stylesheet" /> إلى ملف index.html لم أحصل على تحميل CSS أخترت استخدام "style-loader" عبر "MiniCssExtractPlugin" لتمكين إعادة تحميل لا توجد أخطاء في إخراج وحدة تحكم webpack const path = require('path'); const MiniCssExtractPlugin = require('mini-css-extract-plugin'); const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); const TerserPlugin = require("terser-webpack-plugin"); module.exports = (env, options) => { const mode = options.mode; return { context: __dirname, entry: { script: './src/index.bundle.ts', style: './src/index.bundle.less', }, output: { filename: '[name].js', path: path.resolve(__dirname, './src/dist') }, devServer: { watchFiles: ['src/**/*.less'], static: { directory: path.join(__dirname, 'src'), watch: true, }, compress: true, port: 9000, hot: true, }, devtool: 'source-map', resolve: { extensions: ['.ts', '.tsx', '.js', '.css', '.less'] }, plugins: [ new MiniCssExtractPlugin({ filename: '[name].css', chunkFilename: '[id].css', ignoreOrder: false, }), ], module: { rules: [{ test: /\.js$/, exclude: /node_modules/, use: { loader: 'babel-loader', options: { target: 'browserslist' } } }, { test: /\.ts(x)?$/, loader: 'ts-loader', exclude: /node_modules/ }, { test: /\.css$/, use: [ mode === 'production' ? MiniCssExtractPlugin.loader : 'style-loader', { loader: 'css-loader', }, { loader: 'postcss-loader', // Run postcss actions options: { postcssOptions: { config: path.resolve(__dirname, "postcss.config.js"), } } }, ] }, { test: /\.less$/, use: [ mode === 'production' ? MiniCssExtractPlugin.loader : 'style-loader', 'css-loader', 'less-loader' ] }, ] }, optimization: { minimize: true, minimizer: [new TerserPlugin(), new CssMinimizerPlugin()] }, target: 'web', } };1 نقطة
-
1 نقطة
-
من خلال تعلمك لغة php أو غيرها من اللغات سوف تتعلم الخوارزميات والداتا ستركشر ولكن ربما تواجهك بعض الصعوبات والمشاكل سببها عدم فهمك للداتا ستركشر الذي تتعامل معه, من خلال حل للمشكلة التي واجهتك سوف تتعلم الداتا ستركشر1 نقطة
-
كبداية في لغة c يعتبر امر جيد, يمكنك من خلالها معرفة أساسيات البرمجة والتعرف على مختلف المصطلحات التي سوف تتكرر معك في جميع اللغات مثل المتغيرات والمصفوفات وحلقات التكرار وجمل الشرط, تقريبا تتبع نفس المبدا في كل اللغات, لذلك كبداية في لغة c يعتبر أمر جيد, يمكنك أيضا البداية بلغة جافا أو c++ والبدء بهما أفضل من البدء بلغة c لأنك من خلالها ستتعرف على البرمجة كائنية التوجه والتي سوف تواجهك في php , بعد ذلك يمكنك الدخول في دورة تطوير تطبيقات الويب باستخدام لغة PHP, الجدير بالذكر أنه حتى لو لم يكن لديك أي خبرة بالبرمجة من قبل سوف يتم توضيح كل شيء والبداية من الصفر في هذه الدورة, يمكنك بعدها أن تكون backend جيد, ولكن يفضل قبل البداية في هذا المسار أن يكون لديك معرفة بجزء الفرونت اند, لكي تستطيع توظيف قسم الباك اند مع الفرونت اند وسوف تواجه صعوبات كثيرة اذا لم تكن على معرفة ولو بسطية في html , بالنسبة الخوارزميات فهي مهمة ويفضل أن يكون لديك معرفة بها, من خلالها سوف تستطيع أفضل الحلول للمشاكل التي تواجهك وأيهما أسرع , فالسرعة مهمة في المواقع والبرمجة بشكل عام, أما الداتا ستركتشر مهمة جدا لكي تستطيع تحديد نوع البيانات التي تتعامل معها, أثناء تعلم php سوف تلاحظ هذه الأشياء وسوف تلاحظ أن الداتا ستركتشر مهمة جدا1 نقطة
-
أحاول البحث عن كائنات من نموذج User من خلال قيمة الحقل DateTimeField. من خلال الكود التالي: User.objects.filter(datetime_registred=datetime.date(2021,9,12)) أحصل على كائن queryset فارغ، أعتقد لأنني لم أحدد وقت في عملية البحث، حيث وضعت تاريخ فقط، لكنني أريد أي وقت خلال اليوم المحدد. أي أني أريد تحديد كل المستخدمين الذين سجلوا خلال هذا اليوم هل هناك طريقة سهلة في Django للقيام بذلك؟1 نقطة
-
في next.config.js الخاص بي ، لدي التكوين التالي const withCSS = require('@zeit/next-css'); const withSass = require('@zeit/next-sass'); const withImages = require('next-images'); const withFonts = require('next-fonts'); module.exports = withCSS( withSass( withFonts(), // <=== هل هذا صحيح؟ withImages({ distDir: '../_next', webpack(config) { return config; } }) ) );1 نقطة
-
الاخطاء المذكورة من قبل الزملاء ستحل المشكلة لديك لكن يمكنك تحسين الشيفرة قليلا بالنسبة للخانات التي تحتاج value const idsValuesForm1 = { 'app_time-1': '08:45 - 09:00', 'first_name-1': 'test', 'last_name-1': 'test', .... }; for (const [key, value] of Object.entries(idsValuesForm1)) { document.getElementById(key).value = value; } const idsValuesForm2 = { 'app_time-2': '08:45 - 09:00', 'first_name-2': 'test', 'last_name-2': 'test', ..... }; for (const [key, value] of Object.entries(idsValuesForm2)) { document.getElementById(key).value = value; }1 نقطة
-
في الطبيعي يكون رد مصادقة simpleJWT من جانغو Django مشابه للتالي: { "refresh":"" "access": "" } كيف يمكنني أن أعدل على الرد السابق لكي أضيف خصائص آخرى مثل: { "username": "", "detail": "", "accessToken": "", "refreshToken": "" }1 نقطة
-
يمكنك كتابة طريقة العرض الخاصة بك للـ API إذا كنت تريد تخصيصه، ولا تحتاج إلى استخدام العرض الموجود مسبقًا from rest_framework_simplejwt.tokens import RefreshToken def get_tokens_for_user(user): refresh = RefreshToken.for_user(user) return { 'refresh': str(refresh), 'access': str(refresh.access_token), } ستعيد الدالة get_tokens_for_user أعلاه serialized لرمز refresh token وaccess token للمستخدم المحدد (المدخل إلى الدالة). بشكل عام، يمكن إنشاء token لأي فئة فرعية subclass من rest_framework_simplejwt.tokens.Token بهذه الطريقة.1 نقطة
-
يمكنك أن تستخدم الخاصية contains على النحو التالي: User.objects.filter(datetime_registred__contains=datetime.date(2021,9,12)) أو يمكنك تحديد السنة والشهر واليوم يدويًا، وبالتالي سيتم تحديد كل المستخدمين الذين سجلوا في الموقع في هذا اليوم فقط بغض النظر عن وقت التسجيل: User.objects.filter(datetime_published__year='2021', datetime_published__month='09', datetime_published__day='12') وإن كنت تستخدم الإصدار 1.9 أو احدث من جانغو Django فيمكنك أن تستخدم الخاصية date، كالتالي: User.objects.filter(datetime_registred__date=datetime.date(2021, 9, 12))1 نقطة
-
يمكنك استخدام الدالة model._meta.get_all_field_names() #استخدام الكود التالي عوضا اذا كنت تستخدم نسخه 1.9 model._meta.get_fields() لعرض اسماء الحقول في النموذج. كذلك يمكنك استخدام: model._meta.get_field() لتستطيع التعامل مع اسماء verbose. ويمكنك استخدام: etattr(model_instance, 'field_name') للتعامل مع قيم الحقول1 نقطة
-
يوفر جانغو Django طريقة للحصول على أسماء الحقول وقيمها أيضًا من خلال التابع get_fields والذي يقوم بإرجاع tuple من أسماء الحقول، ويمكنك إستخدامه كالتالي: from django.contrib.auth.models import User fields = User._meta.get_fields() for field in fields: print(field.name) وإن كنت تريد المرور على كل الكائنات في نموذج معين فيمكنك أن تستخدم serializers، على النحو التالي: from django.core import serializers users = serializers.serialize("python", User.objects.all()) ثم في القالب: {% for user in users %} {% for field, value in user.fields.items %} {{ field }}: {{ value }} {% endfor %} {% endfor %} وإن أردت عرض حقول معينة، فيمكنك إضافة الخاصية fields، كالتالي: from django.core import serializers users = serializers.serialize("python", User.objects.all(), fields=('name','email'))1 نقطة
-
الJWT(JSON web Token) ليست أفضل من الsessions في المطلق, وإنما تقوم بحل بعض المشكلات التي تنتج من إستخدامنا للsessions أو بالأدق المشاكل التي تنتج من إعتمادنا على المصادفة من خﻻل الخادم (server-side authentication) من تلك المشاكل: تخزين الsessions, حيث يكون لنا خيارين , إما تخزينها في قواعد البيانات والذي يؤدي إلى زيادة التكلفة وضعف في الأداء نسبياً الخيار الثاني هو تخزينها في الذاكرة , وذلك ليس حل فعال إن كان التطبيق يتم خدمته من خﻻل أكثر من خادم على أكثر من حاسوب , لأن الذاكرة ليست مشتركة مما قد يسبب مشاكل وأخطاء في عملية المصادقة أما بالنسبة للjwt فيكون الtoken مُخزن على حاسوب العميل فﻻ يحتاج الخادم إلى تخزينه وﻻ تقابلنا المشاكل السابقة , إذا للjwt المميزات الأتية أقل في التكلفة حيث لا يحتاج إلى قاعدة بيانات في الأغلب للتخزين ﻻمركزي, بمعنى أن الرموز(tokens) ليست موجودة في مكان واحد (الخادم) وإنما كل عميل يحمل الرمز الخاص به ولكن على الجانب الأخر نجد تحديات عند إستخدام الرموز(tokens) تأمين عملية تخزين الرموز, بما أنها مُخزنة على حاسوب العميل فهذا يجعلها أقل أماناً ويصنع تحدي في عملية الحفاظ عليها تأمين عملية نقلها عبر الشبكة, حيث أنها تُرسل من قِبل العميل فيُمثل أمر إنتقالها بدون أن يتم التجسس عليها تحدياً بالنسبة للمطورين عملية تحديد الرموز كغير صالحةinvalid يُعد من الأمور الشاقة نسبياً بالنسبة للمصادقة عبر الجلسات sessions authentication1 نقطة
-
للحصول على حل يعمل أيضا حتى عندما يكون لديك UUIDField كمفتاح أساسي يمكنك توصيل إشارة post_save من Django. أضف الكود التالي إلى models.py: from django.db.models.signals import post_save from django.dispatch import receiver @receiver(post_save, sender=MyModel) def mymodel_saved(sender, instance, created, **kwargs): if created: # قم بعمل إضافي في المثال الخاص بك ، على سبيل المثال # instance.generate_avatar()=> عمل # instance.send_email_notification()=> إرسال إشعار البريد الإلكتروني pass سيؤدي رد الاتصال هذا إلى حظر طريقة الحفظ ، بحيث يمكنك القيام بأشياء مثل تشغيل الإشعارات أو تحديث النموذج بشكل أكبر قبل إرسال الرد، سواء كنت تستخدم النماذج أو إطار عمل Django REST لطلبات AJAX.1 نقطة
-
إذا كنت تستخدم معالج السياق "request" وقمت بتثبيت البرنامج الوسيط site فإنك تستطيع فعل ذلك في ملف الاعدادات INSTALLED_APPS = [ ... "django.contrib.sites", ... ] MIDDLEWARE = [ ... "django.contrib.sites.middleware.CurrentSiteMiddleware", ... ] الآن سيكون لديك كائن request متاحا في القوالب ويمكنك استخدامه، وأيضا سيحتوي على مرجع للموقع الحالي, يمكنك الحصول على domain في القالب باستخدام {{request.site.domain}} كما يمكنك الحصول على اسم الموقع كالتالي {{request.site.name}}1 نقطة
-
كما يمكنك القيام بذلك بالشكل التالي (هذه الطريقة ليست جيدة للانتاج): #view ضمن ال request.scheme # http or https request.META['HTTP_HOST'] # example.com request.path # /some/content/1/ #template ضمن ال {{ request.scheme }} :// {{ request.META.HTTP_HOST }} {{ request.path }} حل آخر: يتأكد SimpleLazyObject من أن استدعاء قاعدة البيانات سيحدث فقط عندما يستخدم القالب بالفعل كائن الموقع. يؤدي ذلك إلى إزالة الاستعلام من صفحات المسؤول. كما أنه يخزن النتيجة مؤقتاً: from django.utils.functional import SimpleLazyObject from django.contrib.sites.shortcuts import get_current_site def site(request): return {'site': SimpleLazyObject(lambda: get_current_site(request)),} وقم بتضمينه في الإعدادات: TEMPLATE_CONTEXT_PROCESSORS = ( "module.context_processors.site", .... ) وفي القالب يمكنك استخدام {{site.domain}} للحصول على المجال الحالي.1 نقطة
-
لا يكفي التحقق من self.pk == None لتحديد ما إذا كان سيتم إدراج الكائن أو تحديثه في قاعدة البيانات. الكائن الذي تم إنشاؤه حديثاً (self) يحتوي على قيمة pk يمكنك أن تتحقق من وجود self.id وال flag (العلم) force_insert. كما يلي: if not self.pk or kwargs.get('force_insert', False): self.created = True #save استدعاء دالة super(self.__class__, self).save(*args, **kwargs) #التالي if ضمن بلوك post save قم بتنفيذ كل إجراءات ال if getattr(self, 'created', False): # Statements1 نقطة
-
يمكنك استخدام bulk_update بسهولة لفعل ذلك. في البداية عليك تنزيلها كالتالي: pip install django-bulk-update بعد ذلك يمكنك استخدامها بسهوله كما المثال التالي: from bulk_update.helper import bulk_update random_names = ['Walter', 'The Dude', 'Donny', 'Jesus'] people = Person.objects.all() for person in people: r = random.randrange(4) person.name = random_names[r] bulk_update(people) # تحديث كل الأعمدة من قاعدة البيانات وفي حالتك يمكنك تنفيذها في سطر واحد كالتالي: ModelClass.objects.filter(name='bar').update(name="foo")1 نقطة
-
بالاضافة لطريقة سامح، يمكننا كذلك تفحص حالة self._state حيث انه اذا كانت: self._state.adding is True فهذا يعني انه تم انشاؤه created اما اذا كانت الحالة: self._state.adding is False فهذا يعني انه تم تحديثه updated وبطريقه اخرى يمكنك اضافة تاريخ انشاؤه كالتالي: date_created = models.DateTimeField(auto_now_add=True) والتأكد من وجود التاريخ من عدمه حيث انه اذا لم يوجد تاريخ للانشاء فهذا يعني انه تم تحديثه updated: created = self.date_created is None1 نقطة
-
حسب شروط عمل موقع مستقل وأقتبس: صاحب المشروع: أرجو قراءة كيف يضمن مستقل حقوقك للتأكد ومراجعة قيود وشروط العمل في مستقل. نصيحتي هي محاولة التواصل مع المستقل، وتنبيهه للمشاكل التي تعرضت لها، يمكن أن يقوم بعمل تعديل إن أراد ذلك ولكنه ليس مجبراً، أنت عليك تجربة البرنامج قبل الاستلام والتأكد منه. ربما تفتح مشروعاً جديد مع المستقل نفسه وتطلب منه عمل التعديلات المطلوبة وإصلاح المشاكل مقابل مبلغ بينكم يتم بالاتفاق. المشاكل البرمجية ربما لاتظهر في مرحلة التطوير وهذا شيئ طبيعي، ربما سقط سهواً أي مشكلة ولو بسيطة وسبب عطل لديك. الحل الودي هو الأفضل دوما، ويمكنك التواصل مع الإدارة لربما لهم توصيات. انتبه لقراءة شروط الاستخدام عند شراء أي منتج أو خدمة و تأكد منها، لأن القانون يكون مكتوب في معلومات الموقع ولكي لا تتعرض لخسارة.1 نقطة
-
مرحبًا بك في هذه السلسلة التي سنتحدث من خلالها عن إطار العمل Bootstrap 5 ذلك الإطار الذي يهيمن على معظم عمليات التطوير التي تحدث في الواجهة الأمامية Front-End Development في مواقع الإنترنت عمومًا. لا تفترض هذه السلسلة أن يكون لديك أي فكرة مسبقة عن بوتستراب Bootstrap (ولو أنّ بعض المعرفة القليلة مرحّب بها)، في حين أنّ الإلمام بـ HTML و أساسيات CSS هو أمر ضروري للمتابعة في هذه السلسلة. رغم أنّ بوتستراب يستخدم جافاسكريبت في بعض المكوّنات إلى أنّه ليس من الضروري أن يكون لديك معرفة بها لكي تتعلّم بوتستراب، ولو أنّ الإلمام بجافاسكريبت يُعدّ بديهيًا لمطوري الواجهة الأمامية عمومًا. هذا هو المقال الأوّل في هذه السلسلة، وهو مقال تمهيدي بطبيعة الحال، وفيه سنتحدّث عن النقاط التالية: ماهو بوتستراب؟ مالجديد في بوتستراب 5؟ إعداد بوتستراب للعمل. استخدام محرر برمجي مناسب ما الذي سنبنيه في هذه السلسلة؟ ماهو بوستراب؟ بوتستراب ببساطة هو إطار عمل Framework متكامل مبني على CSS و جافاسكريبت JavaScript يُستخدم لتنسيق صفحات الويب وإكسابها نواح جمالية بدون الحاجة إلى استخدام تنسيقات معقدة من CSS. يدعم بوتستراب مبدأ تنسيق الأجهزة المحمولة أولًا Mobile First Style وهذا يعني توافقية عالية مع الأجهزة المحمولة ذات الشاشات الصغيرة. عندما يُذكر بوتستراب فأول ما يتبادر إلى الذهن هو السرعة والأناقة والسهولة والتصميم المتجاوب Responsive Design مع مختلف أنواع الشاشات. كان أول من طور بوتستراب شركة تويتر الشهيرة، وبعد عام تقريبًا، جعلته مفتوح المصدر ومتاحًا بالكامل من خلال GitHub. يستند بوتستراب كما أشرنا مسبقًا إلى CSS فهو يوفّر كمّا كبيرًا من الجهد لتنسيق المكوّنات في صفحة الويب. يهدف بوتستراب كما هو واضح إلى تبسيط عمليات التصميم التي تحدث في الواجهة الأمامية Front-End وجعلها معيارية. يسهّل هذا الأمر إلى حدّ بعيد من حياة المصممين والمطورين على حدّ سواء، ويجعل عملية انضمام مصمّم جديد إلى فريق العمل في شركة تعتمد بوتستراب أمرًا يسيرًا نسبيًا. استخدام بوتستراب سهل جدًا. فيمكن من خلال إضافة صنف Class أو أكثر إلى عنصر HTML أن تحصل على أثر فوري يحوّل هذا العنصر إلى شكل جميل وعصري. انظر مثلًا إلى شيفرة HTML التالية: <button>مرحبًا</button> سيولّد الكود السابق الزر البسيط التالي: سأضيف الآن صنفان بسيطان من بوتستراب إلى الكود السابق: <button class="btn btn-primary">مرحبًا</button> ستحصل على الشكل الجميل التالي: لاحظ كيف اكتسب هذا الزر الألوان المناسبة بالإضافة إلى حاشية Padding مناسبة أيضًا وبتلقائية حول النص الموجود ضمن الزر. وأيضًا كيف أصبحت حواف الزر منحنية. توجد العديد من التشكيلات الأخرى التي يمكن اكسابها للأزرار كما سنرى فيما بعد. مالجديد في بوتستراب 5؟ يُعَد الإصدار 5 إصدارًا رئيسيًا وهو الأحدث من بوتستراب حاليًا (وقت كتابة هذا المقال)، وكما جرت العادة، فهناك العديد من التغييرات التي طرأت على الإصدار الذي يسبقه (الإصدار 4) فمثًلا فقد أزيل المكوّن Jumbotron بالإضافة إلى إزالة الدعم عن المتصفحين IE 10 و IE 11، وأيضًا أزيل عدد من أصناف التنسيق التي كانت موجودة في الإصدار 4. هناك تغييرات أخرى قد حدثت ضمن مخطط الصفحة حيث أضيف قياس آخر جديد لم يكن موجودًا في الإصدار السابق وهو القياس xxl. و توجد تحسينات أخرى في نظام الألوان. كما أضيف دعم أيقونات SVG جميلة ومتنوّعة ومفتوحة المصدر أيضًا. يمكنك مع مكتبة الأيقونات هذه الاستغناء عن مكتبات أيقونات إضافية مثل Font Awesome. في الإصدار 5 أيضًا لم يعد هناك حاجة لاستخدام المكتبة jQuery بعد الآن (بعض المزايا الموجودة في بوتستراب تحتاج إلى جافاسكريبت)، فقد انتقل مطوّرو بوتستراب إلى استخدام جافاسكريبت فقط، مع إمكانية الإبقاء على استخدام jQuery في حال الرغبة. أود أن أركّز هنا على ميزة مهمة أضيفت إلى بوتستراب 5، طالما انتظرها المصممين والمطورين العرب! وهي دعم الاتجاه من اليمين إلى اليسار RTL مما يسهّل حياتهم إلى حدّ كبير. إعداد بوتستراب للعمل يمكن تضمين بوتستراب في صفحة الويب التي نعمل بها بإدراجه عن طريق العنصر link ضمن العنصر head في ترويسة الصفحة، ويمكن اختيار تضمين بوتستراب من مزوّد محتوى على الإنترنت CDN وهو الخيار الأفضل. ومن الممكن كذلك تنزيل نسخة من بوتستراب محليًا ومن ثمّ تضمينها ضمن صفحة الويب التي تعمل بها. سنعمل في هذه السلسلة على الخيار الأول، أي أنّنا سنستخدم مزوّد محتوى CDN. سنعتمد القالب الأساسي التالي أثناء عملنا على بوتستراب: <!doctype html> <html lang="en"> <head> <!-- Required meta tags --> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- Bootstrap CSS --> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous"> <title>Hello, world!</title> </head> <body> <h1>السلام على الجميع</h1> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script> </body> </html> لاحظ أنّه وقبل نهاية وسم الإغلاق </body> وضعنا الوسم <script> الذي يسمح بتحميل كود جافاسكريبت الذي تحتاجه بعض مكوّنات بوتستراب لكي تعمل عملًا صحيحًا. استخدام محرر برمجي مناسب توجد العديد من الخيارات المتاحة لاستخدام محرّر برمجي مناسب في سياق عملك كمطوّر واجهة أمامية، ومن المحرّرات الشهيرة Visual Studio Code و Sublime و Atom. بالنسبة لي أفضل استخدام Visual Studio Code من مايكروسوفت لما يتمتع به من مرونة ودعم كبيرين. لتثبيت محرر vs code انتقل إلى الموقع الخاص به لتنزيله. سيظهر زر التحميل في الصفحة الرئيسية. عندما تنتهي من تنزيله وتثبيته، افتحه وانتقل إلى قسم الإضافات Extensions ضمنه في الشريط الموجود على الناحية اليسرى كما في الشكل التالي: بعد ذلك وفي خانة البحث في الأعلى اكتب Live Server للبحث عن هذه الإضافة التي ستسمح لك بتشغيل خادوم مبسّط على حاسوبك الشخصي مما يسمح لنا بتجريب الشيفرة التي نكتبها مباشرةً على المتصفح الافتراضي الموجود على حاسوبنا. بعد اختيار الإضافة انقر الزر Install في الناحية الخاصة بشرح الإضافة (في الطرف الأيمن) لتثبيتها. بنفس الأسلوب السابق تمامًا ننصحك بتثبيت إضافة Auto Rename Tag، حيث تساعد هذه الإضافة على التعديل التلقائي لوسم ما عند تعديل الوسم المرافق له. ما الذي سنبنيه في هذه السلسلة؟ سنبني في هذه السلسلة موقع ويب بسيط عبارة عن صفحة واحدة يمكن أن يُعتبر كقالب يشرح مزايا بوتستراب 5 التي سنتناولها تباعًا أثناء تقدمنا في هذه السلسلة. هذا الموقع عبارة عن موقع يبيع دورات تعليمية على الإنترنت. يوفر الموقع إمكانية التسجيل الجديد للمستخدمين بالإضافة إلى تسجيل دخول للمستخدمين السابقين. كما سيعرض آخر الدورات التدريبية (المنتجات) المتوفرة، وأيضًا الدورات الأكثر مبيعًا. كما سنوفّر ميزة سلة المشتريات التي تسمح للمستخدم بالتسوّق من خلال اختيار الدورات التي يرغب بشرائها. بالإضافة إلى ما سبق سنضيف بعض الأقسام على الصفحة الرئيسية التي توفّر بعض المعلومات عن الموقع وبنفس الوقت توضّح لنا كيفية استخدام مزايا بوتستراب 5 المتنوّعة. سنعمل على بناء هذا الموقع شيئًا فشيئًا أثناء عملنا في هذه السلسلة. انظر إلى الشكل التالي الذي يعطيك شكلًا تقريبيًا لما سنحصل عليه في نهاية هذه السلسلة. مصدر الصور في آخر هذه السلسلة سنتعلّم كيف نرفع الموقع كاملًا على إحدى الإستضافات لكي يصبح بالإمكان معاينته بصورة حية. اقرأ أيضًا 10 أخطاء شائعة عند استخدام إطار العمل Bootstrap بناء قائمة شجرية باستخدام البوتستراب تصميم صفحة موقع باستخدام 3 Bootstrap - الجزء الأول1 نقطة
-
Harmony هو الاسم الرمزي لـ ECMAScript 6 وهي اللغة القياسية التي تقوم عليها JavaScript، والإصدار الجديد يأتي بميزات جديدة تتناول العديد من جوانب اللغة بما فيها الصياغة (syntax) وأسلوب البناء وأنواع جديدة من المكونات المدمجة في اللغة. في هذا المقال نتعرف على بعض من المميزات التي ستجعل كتابة شيفرة جافاسكربت أكثر اختصاراً وفعالية. متغيرات نطاقها القطعة البرمجية (Block-scoped Variables)في الإصدار الحالي من JavaScript، تُعامل كل المتغيرات المفروضة ضمن دالة (function) على أنها تابعة لهذه الدالة (Function-scoped) أي يمكن الوصول إليها من أي موقع ضمن هذه الدالة، حتى وإن كانت هذه المتغيرات قد فُرضِت ضمن قطعة برمجية فرعية ضمن هذه الدالة (كحلقة for أو جملة شرطية if)، وهذا يخالف ما تتبناه بعض من أشهر لغات البرمجة، وقد يسبب بعض الارتباك لمن لم يعتد عليه. لنوضح أكثر في هذا المثال: var numbers = [1, 2, 3]; var doubles = []; for (var i = 0; i < numbers.length; i++) { var num = numbers[i]; doubles[i] = function() { console.log(num * 2); } } for (var j = 0; j < doubles.length; j++) { doubles[j](); }عند تنفيذ هذا المثال، سنحصل على الرقم 6 ثلاث مرات، وهو أمر غير متوقع ما لم نكن على معرفة بطبيعة مجالات JavaScript، ولو طبق ما يشبه هذا المثال في لغة أخرى، لحصلنا على النتيجة 2 ثم 4 ثم 6، وهو ما يبدو النتيجة المنطقية لشيفرة كهذه. ما الذي يحدث هنا؟ يتوقع المبرمج أن المتغير num محصور ضمن حلقة for وعليه فإن الدالة التي ندخلها في المصفوفة doubles ستعطي عند استدعائها القيمة التي ورثتها عن مجال حلقة for إلا أن الحقيقة هي أن المتغير num يتبع للمجال العام، لأن حلقة for لا تُنشئ مجالًا فرعيًّا وعليه فإن القيمة العامة num تتغير ضمن حلقة for من 2 إلى 4 إلى 6 وعند استدعاء أي دالة ضمن المصفوفة doubles فإنها ستعيد إلينا القيمة العامة num، وبما أن الاستدعاء يحدث بعد إسناد آخر قيمة للمتغير num، فإن قيمته في أي لحظة بعد انتهاء الحلقة الأولى ستكون آخر قيمة أسندت إليه ضمن هذه الحلقة، وهي القيمة 6. يعطينا الإصدار القادم طريقة لحل هذا الارتباك باستخدام الكلمة المفتاحية let بدلاً عن var، وهي تقوم بخلق مجال ضمن القطعة البرمجية التي تُستخدم فيها، بمعنى آخر: ستكون let هي بديلنا عن var من الآن فصاعدًا، لأنها ببساطة تعطينا النتائج البديهية التي نتوقعها. لنُعِد كتابة المثال السابق باستبدال var num بـlet num: var numbers = [1, 2, 3]; var doubles = []; for (var i = 0; i < numbers.length; i++) { let num = numbers[i]; doubles[i] = function() { console.log(num * 2); } } for (var j = 0; j < doubles.length; j++) { doubles[j](); }عند تطبيق هذا المثال (يمكنك تطبيقه في Firefox وChrome لأن كلا المتصفحين شرعا في دعم let) سنحصل على النتيجة البديهية 2 ثم 4 ثم 6. بالطبع بإمكاننا تحسين الشيفرة باعتماد let عند التصريح عن كل المتغيرات السابقة، وهو الأمر الذي يجب أن تعتاد فعله من اليوم! شيفرة أقصر وأسهل للقراءةلعل أكثر ما أُحبّه في JavaScript مرونتها الفائقة، وبالذات القدرة على إمرار دوال مجهولة (Anonymous Functions) لدوال أخرى، الأمر الذي يسمح لنا بكتابة شيفرة ما كان من الممكن كتابتها بلغات أخرى إلا بضعفي عدد الأسطر وربما أكثر. لاحظ هذا المثال: var people = ['Ahmed', 'Samer', 'Khaled']; var greetings = people.map(function(person) { return 'Hello ' + person + '!'; }); console.log(greetings); // ['Hello Ahmed!', 'Hello Samer!', 'Hello Khaled!'];لو أردنا تنفيذ هذه المهمة في لغة أخرى، فلربما احتجنا إلى حلقة for لنمرّ من خلالها على كل عنصر ضمن المصفوفة ثم إدخال العبارات الجديدة ضمن مصفوفة أخرى، وهذا يعني أن مهمة يمكن كتابتها بسطرين في JavaScript قد تتطلب 5 سطور في لغة أخرى. لو لم تمتلك JavaScript القدرة على إمرار الدالة المجهولة function(person) {...} أعلاه، لفقدت جزءًا كبيرة من مرونتها. لكن الإصدار القادم من JavaScript تذهب أبعد من ذلك، وتختصر علينا كتابة الكثير من النص البرمجي. لُنعد كتابة المثال السابق: let people = ['Ahmed', 'Samer', 'Khaled']; let greetings = people.map(person => 'Hello ' + person + '!'); console.log(greetings); // ['Hello Ahmed!', 'Hello Samer!', 'Hello Khaled!'];في هذا المثال استخدمنا ما اصطلح على تسميته دوال الأسهم (Arrow Functions)، وهي طريقة أكثر اختصارًا لكتابة الدوال المجهولة، لن تحتاج لكتابة return، فهي ستضاف تلقائيًا عند التنفيذ. من الآن فصاعداً اعتمد دوال الأسهم عندما تريد تنفيذ دالة مجهولة بسيطة بسطر واحد. بمناسبة الحديث عن الشيفرة المختصرة... ما رأيكم لو جعلنا الشيفرة أعلاه أكثر اختصارًا؟! let people = ['Ahmed', 'Samer', 'Khaled']; let greetings = ['Hello ' + person + '!' for (person of people)]; console.log(greetings); // ['Hello Ahmed!', 'Hello Samer!', 'Hello Khaled!'];قد تبدو الصياغة غريبة بعض الشيء، لكنها تتيح لنا فهم النص بسهولة أكبر، وتغنينا عن الحاجة لدالة مجهولة (الأمر الذي قد يؤثر على الأداء، وإن كان بأجزاء من الثواني). الصياغة التي استخدمناها أعلاه تُسمى Array Comprehensions، وإن كنت قادرًا على ترجمتها إلى العربية بطريقة واضحة، فلا تبخل بها علينا! لكن... ألا ترون أنه يمكن تحسين هذه الشيفرة قليلاً؟ let people = ['Ahmed', 'Samer', 'Khaled']; let greetings = [`Hello ${ person }!` for (person of people)]; console.log(greetings); // ['Hello Ahmed!', 'Hello Samer!', 'Hello Khaled!']; هنا استبدلنا إشارات الاقتباس (' أو ") بالإشارة ` الأمر الذي أتاح لنا إحاطة المتغير person بقوسين معكوفين مسبوقين بإشارة $، وهذه الصياغة تدعى "السلاسل النصية المقولبة" أو Template Strings، والتي تسمح -بالإضافة إلى القولبة- بالعديد من الأشياء الرائعة، كالعبارات على عدة أسطر: let multilineString = `I am a multiline string`; console.log(multilineString); // I am // a multiline // string للأسف لن تعمل الشفرة السابقة في أي من المتصفحات الحالية، لأن السلاسل النصية المقولبة ما تزال غير معتمدة ضمن أي منها. تحديث: بدأ Firefox Nightly باعتمادها. من المميزات الجديدة كذلك إمكانية اختصار بناء الكائنات ذات الخصائص بالشكل التالي: حاليًا، نقوم بكتابة شيفرة مثل هذه: var createPerson = function(name, age, location) { return { name: name, age: age, location: location, greet: function() { console.log('Hello, I am ' + name + ' from ' + location + '. I am ' + age + '.'); } } }; var fawwaz = createPerson('Fawwaz', 21, 'Syria'); console.log(fawwaz.name); // 'Fawwaz' fawwaz.greet(); // "Hello, I am Fawwaz from Syria. I am 21." في الإصدار القادم، سيكون بالإمكان كتابة الشيفرة كالتالي:let createPerson = function(name, age, location) { return { name, age, location, greet() { console.log('Hello, I am ' + name + ' from ' + location + '. I am ' + age + '.'); } } }; let fawwaz = createPerson('Fawwaz', 21, 'Syria'); console.log(fawwaz.name); // 'Fawwaz' fawwaz.greet(); // "Hello, I am Fawwaz from Syria. I am 21."بما أن اسم المُعامل (parameter) يماثل اسم الخاصة (property)، فإن هذا يتم تفسيره على أن قيمة الخاصة توافق قيمة المعامل، بمعنى: name: name، بالإضافة إلى كتابة greet() {...} بدل greet: function() {...}. كذلك سيكون بإمكاننا تحسين هذا النص أكثر من ذلك باستخدام الأصناف (Classes)، نعم! سيكون لدينا أصناف أخيرًا! (سنستعرضها لاحقاً) الثوابت (Constants)سيداتي وسادتي... رحبوا بالثوابت... نعم إنها أخيرًا متوفرة في JavaScript، إحدى المكونات الأساسية لأي لغة برمجية التي لم تكن متوفرة في JavaScript، أصبحت الآن متوفرة. والآن نأتي للسؤال البديهي: لماذا أحتاج للثوابت؟ أليس بإمكاني التصريح عن متغير دون أن أغير قيمته بعد إعطاءه القيمة الأولية؟ نعم بالطبع بإمكانك ذلك، لكن هذا لا يعني بالضرورة أن المستخدم أو نصاً برمجيًا من طرف ثالث ليس بإمكانه تغيير قيمة هذا المتغير في سياق التنفيذ، وطالما أن المتغير "متغير" بطبيعته، فإننا دومًا بحاجة إلى شيء من أصل اللغة يحمينا من تغييره خطأ. عند التصريح عن ثابت فإننا نعطيه قيمة أولية ثم ستتولى الآلة البرمجية لـJavaScript حماية هذا الثابت من التغيير، وسُيرمى خطأ عند محاولة إسناد قيمة جديدة لهذا الثابت. const myConstant = 'Never change this!'; myConstant = 'Trying to change your constant'; // TypeError: redeclaration of const myConstant console.log(myConstant); // "Never change this!" المُعاملات الافتراضية (Default Parameters)غياب دعم المُعاملات الافتراضية في JavaScript واحد من أكثر الأشياء التي تزعجني، لأنها تجبرني على كتابة شيفرة مثل هذه: function SayHello (user) { if (typeof user == 'undefined') { user = 'User'; } console.log('Hello ' + user); } console.log(SayHello('Fawwaz')); // Hello Fawwaz! console.log(SayHello()); // Hello User!لو كان عندي 3 متغيرات غير إجبارية، فهذا يعني أنني سأحتاج 3 جمل شرطية، الأمر الذي يتطلب الكثير من الكتابة المُملة. بفضل الإصدار القادم من JavaScript، سيكون بالإمكان كتابة شيفرة أبسط بكثير: function SayHello (user='User') { console.log('Hello ' + user); } SayHello('Fawwaz'); // Hello Fawwaz! SayHello(); // Hello User! الوعود (Promises)الوعود هي الحل الذي تأتينا به JavaScript لحل مشكلة هرم الموت (Pyramid of Death) الذي نواجهه عند تنفيذ مهمات غير متزامنة تعتمد إحداها على الأخرى: function getFullPost(url, callback) { var getAuthor = function(post, callback) { $.ajax({ method: 'GET', url: '/author/' + post.author_id }, callback); }; var getRelatedPosts = function(post, callback) { $.ajax({ method: 'GET', url: '/related/' + post.id }, callback); }; $.ajax({ method: 'GET', url: url }, function(post) { getAuthor(post, function(res) { post.author = res.data.author; getRelatedPosts(post, function(res) { post.releated = res.data.releated; callback(post); }); }); }); } هل تلاحظ أن الشيفرة تتجه نحو اليمين؟ لو أردنا تنفيذ هذه المهمات غير المتزامنة واحدة بعد الأخرى وكان عددها 10 مثلًا فستصبح الشيفرة شديدة التعقيد، كما أن هذه الطريقة ليست بديهية، ولا يمكن لك أن تفهم ماذا تفعل هذه الدالة المجهولة (المعامل الثاني في كل دالة) ما لم تألفها. ماذا لو أمكننا كتابة هذه الشيفرة بصورة أفضل؟ function getFullPost(url) { var post = { }; var getPost = function(url) { return $http.get(url); }; var getAuthor = function(post) { return $http.get('/author/' + post.author_id).then(function(res) { post.author = res.data.author; }); }; var getRelatedPosts = function(post) { return $http.get('/related/' + post.id).then(function(res) { post.related = res.data.related; }); }; return getPost().then(getAuthor).then(getRelatedPosts).catch(function(err) { console.log('We got an error:', err); }); } في الجزء القادم سنتعرّف على المكوّنات الجديدة الأكثر إثارة، كالمولّدات التي ستجعلنا نغير من طريقة تعاملنا مع البيانات اللامتزامنة كليًّا!1 نقطة