البحث في الموقع
المحتوى عن 'تحكم'.
-
في الدروس السابقة تعرّفنا على OneNote وكيفية استخدامه لحفظ أنواع كثيرة من الملاحظات وكيفية تنظيمها في دفاتر الملاحظات، المقاطع، والصفحات. وبما أنّ الصفحات هي الجزء الأساسي الذي ستضيف ملاحظاتك عليه وترتّبها، تتوفر مجموعة من الأدوات والخصائص للتحكّم في طريقة عرض الصفحات وتغيير إعدادها لتسهيل قراءة المعلومات أو إضافتها. يمكن الوصول إلى جميع الأوامر الخاصة بطريقة عرض الصفحة أو إعدادها من تبويب View. الطريقة الافتراضية لعرض الصفحات هي طريقة العرض العادية Normal View وسنستعرض كيفية تغييرها إلى طرق العرض الأخرى وكيفية استخدام خيارات إعداد الصفحة. Full Page View يعمل هذا الخيار على توسيع أبعاد الصفحة إلى أقصى حدّ ممكن بجعلها تملأ الشاشة (أي وضع ملء الشاشة). ويمكنك استخدامه عندما تصبح الصفحة مزدحمة بالعناصر وترغب في توفير المزيد من المساحة لترتيبها. يتم تشغيل هذا الوضع بالنقر على أمر Full Page View من تبويب View (أو بطريقة مختصرة بواسطة النقر على زر السهمين المتعاكسين في زاوية الصفحة العليا اليمنى): عند تشغيل وضع ملء الشاشة يتم إخفاء كل ما حول حدود الصفحة، كتبويبات الأدوات، تبويبات المقاطع، جزء الصفحات، وغيرها، مع الإبقاء على قائمة منسدلة في الأعلى للتنقّل بين المقاطع ودفاتر الملاحظات: يمكنك إظهار تبويبات الأدوات أثناء تشغيل وضع ملء الشاشة بالنقر على النقاط الثلاثة في الأعلى. أمّا للعودة إلى طريقة العرض العادية فانقر على زر السهمين المتعاكسين من جديد: Dock to Desktop يعمل هذا الخيار على تصغير نافذة OneNote إلى حد معيّن وتثبيته على أحد جوانب سطح المكتب، مما يتيح لك إمكانية فتح برامج أخرى والعمل عليها واستعراض ملاحظاتك في نفس الوقت. وبهذه الطريقة أيضًا يمكنك إضافة محتوى إلى صفحات OneNote عن طريق السحب والإفلات. لتشغيل طريقة العرض هذه انقر على أمر Dock to Desktop من تبويب View: ستلاحظ أنّ نافذةOneNote المصغّرة ستبّقى مثبّتة في نفس المكان على الشاشة وبمستوى فوق جميع النوافذ التي ستفتحها. للعودة إلى طريقة العرض العادية، انقر على السهمين المتعاكسين في الجزء العلوي من نافذة OneNote المصغرة: ملاحظة: بإمكانك إضافة الخيار Dock to Desktop إلى شريط أدوات الوصول السريع بالنقر عليه بزر الفأرة الأيمن واختر Add to Quick Access Toolbar: تعديل إعدادات الصفحة في مجموعة Page Setup تتوفر المزيد من الخيارات للتحكم في تخطيط الصفحة ومظهرها. تغيير اللون اللون الافتراضي لخلفية صفحات OneNote هو الأبيض، لكن إذا كنت تفضّل لونًا ثانيًا، بإمكانك الاختيار من مجموعة الألوان في قائمة Page Color: انقر على اللون المرغوب لتطبيقه، وإذا أردت العودة إلى اللون الافتراضي انقر على No Color. تسطير الصفحة تسطير الصفحة وإظهار خطوط الشبكة من الخيارات المفيدة التي تساعدك على ترتيب العناصر ومحاذاتها في الصفحة. فإذا أردت إضافة سطور للصفحة، انقر على Rule Lines واختر التباعد المرغوب للسطور من مجموعة Rule Lines: أمّا لإظهار خطوط الشبكة فانقر على Rule Lines واختر حجم الشبكة المرغوب من مجموعة Grid Lines، علمًا أنّه لا يمكن تطبيق خياري التسطير وخطوط الشبكة معًا في نفس الوقت: إخفاء عنوان الصفحة إذا كنت تفضّل إزالة عنوان الصفحة وما يرافقه من معلومات الوقت والتاريخ واستغلال المساحة التي يشغلها لإضافة الملاحظات انقر على Hide Page Title: سيظهر لك مربّع حوار لتأكيد رغبتك في إزالة العنوان، انقر على Yes للمواصلة: للتراجع عن إزالة العنوان اضغط على مفتاحي Ctrl+ Z من لوحة المفاتيح، أو انقر مجددًا على أمر Hide Page Title ثم قم بإدخال العنوان. حجم الورقة يتضّمن أمر Paper Size خيارات أخرى للتحكّم في حجم الورقة، اتجاهها (أفقي أو عمودي)، اتجاه الصفحة (من اليمين إلى اليسار أو بالعكس)، الهوامش، وغيرها. ويمكن الوصول إلى هذه الخيارات من جزء Paper Size الذي يظهر عند النقر على أمر Paper Size: تتوفر في قائمة Size أغلب الأحجام القياسية، اختر الحجم المرغوب ثم حدّد اتجاه الورقة من قائمة Orientation. ومن الخيارات في قسم Print Margins يمكنك التحكّم في أبعاد هوامش الصفحة، وهذه تظهر عند الطباعة فقط. أما من قائمة Page body فيمكنك تحديد اتجاه الصفحة من اليمين إلى اليسار أو بالعكس. ملاحظة: عند إجراء أي تغيير على إعدادات الصفحة فإنّه سيُطبّق على الصفحة الحالية فقط. إلى هنا نصل إلى نهاية درسنا. في الدرس القادم سنتعلّم طريقة تصدير، مشاركة وطباعة ملاحظات OneNote.
-
تدير Angular الموارد باستخدام نظام الوحدات، ولهذا السّبب فهي تحتاج أيضًا إلى تقديم طريقةٍ للوصول إلى هذه الموارد المنظّمة ضمن حاويات (container-managed)، حيث تقوم Angular بذلك باستخدام نمطٍ إنشائيّ يُدعى حقن التبعية. إن لم يكن لديك معرفةٌ مسبقةٌ بهذا المفهوم فسأقوم هنا بأفضل ما لديّ لتلخيصه لك: لنفترض أنّك تحتاج إلى الحصول على مَوردٍ (resource) من Angular، المَورد هو الحاوية. للحصول عليه يجب أن تكتب تابعًا يُعرّف وسيطًا له نفس اسم هذا المَورد بالضّبط. تقوم الحاوية باكتشاف التّابع الذي كتبته، وتتعرّف على توافق الوسيط مع المَورد المطلوب، فتقوم بإنشاء نُسخةٍ (instance) من هذا المَورد (أو تقوم بأخذ النُّسخة المنفردة (singleton) من هذا المَورد، إن كان من النّوع المنفرد) ثُمّ تقوم باستدعاء التّابع الخاص بك وجعل هذه النّسخة هي قيمة الوسيط الخاص بالتابع. بما أنّ الحاوية هنا تلعب الدّور الفعّال (على عكس الطلب الذي تقوم به للحصول على نسخة من المَورد)، لذلك يُعتبر حقن التّابعيّة عكسًا للتّحكّم (inversion of control)، ويُقدّم على أنّه تطبيق لمبدأ Hollywood، "لا تكلّمنا، نحن سوف نكلِّمُك". أعتقد بأنّ مخترعي Angular قد اختاروا طريقة حقن التّابعيّة بسبب تاريخ Google الطّويل مع منصّة Java، بيئة برمجة ساكنة يقوم فيها حقنُ التّابعيّة بدورٍ فعّال في عمليّات تغيير الأنواع أثناء وقت التّشغيل. (لقد تخطّت Google الحدود في ذلك إلى درجة أنّها أنشأت إطار عمل Java خاصٍّ بها، Guice، الذي يعتمد على حقن التّابعيّة كُلّيًّا.) أمّا في JavaScript، وهي البيئة المرنة والديناميكيّة، حيث يمكن أن تتغيّر الأنواع أثناء وقت التّشغيل، فقد حظِيَ فيها أسلوب محدّد موضع الخدمة (service locator) البسيط والمباشَر بشعبيّة هائلة عن طريق الواجهة البرمجيّة لـCommonJS، وهي عبارة require المستخدمة في Node.js وbrowserify. والأكثر من ذلك، أنّ الطريقة البدائيّة في القيام بحقن التّابعيّة قد تبيّن أنّ لها نقطة ضعفٍ عند استخدامها في JavaScript من طرف العميل، وذلك بسبب تعديل أسماء الوُسطاء باستخدام المُقصّرات (minifiers). ولنستطيع التّعامل مع هذه المشكلة، من الضّروريّ أن توجد أداة بناءٍ بديلة، أو أن نتعلّم ونستخدم حواشي التّبعيّات، وسنصل إلى ذلك بعد قليل، ولكن لنتعرّف أوّلًا على النّموذج البدائيّ. التبعيات الضمنيةلن نستخدم خارج هذا الفصل للقيام بحقن التّبعيّة غير طريقة التّبعيّات الضّمنيّة لأنّها الأسهل بين جميع الطُّرق. كما ذكرت سابقًا، يمكننا جلب مرجعٍ لأحد الموارد المتاحة عن طريق وضعه كوسيطٍ في تابعنا الإنشائيّ، ولقد قمنا بذلك للمرّة الأولى عندما أضفنا الوسيط scope$ الذي يعطي تابع التّحكّم مرجعًا إلى كائن المجال المنظّمٍ ضمن حاوية (container-managed). يقوم نظام حقن التّبعيّة في Angular بالعثور على نسخةٍ للمَورد المطلوب (أو بإنشاء نسخةٍ لهذا المَورد) وتمريره إلى المتحكّم. لنرى مرّةً أخرى كيف نقوم بذلك على المَورد المدمج في Angular، الخدمة locale$. نحتاج إلى تعريف وحدتنا app لأنّ بعض أمثلة هذا الفصل تستخدم نظام الوحدات. angular.module('app', []);وبعد ذلك سنقوم بتحميل الوحدة عن طريق تمرير اسمها إلى التّوجيه ng-app. (أكرّر التّنبيه إلى أنّ الاسم app ليس إجباريًّا ويمكن استخدام أيّ اسم آخر.) <body ng-app="app"> <!-- الأمثلة توضع هنا --> </body>نحن الآن جاهزون للانطلاق مع مثالنا الأوّل، وبطريقةٍ مماثلةٍ لإضافة الوسيط scope$ سنضيف الوسيط locale$، وستلاحظ Angular هذين الوسيطين وتقوم بحقنهما. تقوم Angular بحقن الموارد داخل التّابع لأنّ هذا التّابع يمثّلُ متحكّمًا. angular.module('app') .controller('LocaleController', function($scope, $locale) { $scope.locale = $locale.id; });داخل جسم المتحكّم قمنا ببساطةٍ بإسناد المتغيّر locale الذي يمكننا تغيير اسمه إلى أيّ اسمٍ آخر، إلى العنصر id من الوسيط locale$ الذي لا يمكننا استخدام اسمٍ آخر له. <p ng-controller="LocaleController"> Your locale is <strong ng-bind="locale"></strong> </p>الناتج: Your locale is en-usيُفترض أن ترى شيئًا مماثلًا لعبارة "Your locale is en-us" في المخرجات. ما الذي سيحدث لو أنّك أضفت الوسيط myResource إلى تابع التّحكّم؟ هل عطّلت عمل المثال؟ هل يمكنك قراءة الخطأ في الـconsole الخاصة بـJavaScript في متصفّحك؟ تعرض أخطاء Angular غالبًا رابطا مفيدا، يمكنك عن طريق هذا الرابط أن تحصل على درسٍ رائع وقصير عن حلّ مشاكل حقن التّبعيّة، انقر على الرّابط السّابق واقرأ الشرح إن أردت. الحواشي (Annotations)تمثّلُ الحاشية في لغة برمجةٍ مثل Java، معلوماتٍ إضافيّة تُضاف إلى الشيفرة المصدريّة ويتجاهلها المترجم. أمّا في سياق الحديث عن حقن التّبعيّة في Angular، فتعني كلمة الحاشية التّصريح عن الموارد التي نريد حقنها بطريقةٍ صريحةٍ تحافظ على أسماء الوسطاء قصيرةً باستخدام أسلوب التّصغير (minification). (استخدام أداة البناء UglifyJS مثالٌ على أسلوب التّصغير.) لنتابع الآن طريقة Angular التي تسمح لنا فيها بإضافة الحواشي إلى التّبعيّات. ng-annotateمن الطرق الملائمة للتخلص من إزعاج مهمّة بناء ما، استخدام مهمّة بناءٍ أخرى. ستقوم أداة البناء ng-annotate بإضافة الحواشي للتّبعيّات، ومن ثمّ ستسمح لنا بمواصلة استخدام طريقة التّبعيّات الضّمنيّة التي شرحناها في الفقرة السّابقة. ستحتاج فقط إلى تشغيل ng-annotate قبل أن تُشغّل المقصّر (minifier) الخاصّ بك. هذه الأداة المركزيّة صُمّمت لتُستخدم عن طريق سطر الأوامر، إلّا أنّه يوجد غلافٌ لها لتفادي التّعامل مع سطر الأوامر، كما يوجد غلافٌ لمعظم أدوات البناء وحزم الأدوات، من ضمنها grunt-ng-annotate وgulp-ng-annotate وbrowserify-ngannotate وng-annotate-webpack-plugin. الحاشية السطريةهناك أسلوبان لكتابة الحواشي، وأكثرهما شُهرةً يُعرف باسم الحاشية السّطريّة (inline annotation)، وهي تتضمّن وضع تابع التّحكّم داخل مصفوفةٍ كما يلي. angular.module('app') .controller('LocaleController', ['$scope', '$locale', function(s, l) { s.locale = l.id; }]);الناتج: Your locale is en-usفي المثال السّابق، قُمت بمحاكاة تأثير التّقصير عن طريق تغيير أسماء الوُسطاء من scope$ و locale$ إلى s وl بالترتيب. بالطّبع لا يمكن لـAngular أن تجد مَوردين لهما الأسماء s وl لو اعتمدنا على أسلوب إضافة الحواشي الضّمنيّ، ولكن هنا، ولأنّ المصفوفة تحوي أسماء الوسطاء الحقيقيّين ستتمكّن من حقنهم بنجاح. إضافة الحاشية بواسطة inject$إن كان قد انتابك شعورٌ بأن طريقة إضافة الحواشي السّطريّة، قبيحة، فالأرجح أنك ستجد الطريقة البديلة هذه أكثر قبحًا. فهي تعتمد على إنشاء عنصرٍ ذا اسمٍ مخصّص، inject$، في التّابع الإنشائيّ، وهذا سبب تسمية الطّريقة بهذا الاسم. var LocaleController = function(s, l) { s.locale = l.id; }; LocaleController['$inject'] = ['$scope', '$locale']; angular.module('app') .controller('LocaleController', LocaleController);الناتج: Your locale is en-usالمهمّ أنّك الآن تعرف الخيارات المتاحة للقيام بإضافة الحواشي. angular.injectorأرجو أن تكون عند هذه النّقطة قد قمت بإضافة ng-annotate إلى بُنيتك، لتتمكّن من استخدام الأسلوب البدائيّ في التّبعيّات الضّمنيّة التي ستراها في هذه السلسلة دون مشاكل. على أيّ حال، إن لم تكن قد قمت بذلك، لديّ اقتراح لك، إلّا أنّه ليس اقتراحًا جادًّا: قم بكتابة تابع require الخاصّ بك، وأفصح عن التّبعيّات الّتي تريد ضمن عمليّة البحث المباشر عن الخدمات، وذلك بدلًا من استخدام أسلوب حقن التّبعيّة. يمكنك القيام بذلك عن طريق استدعاء تابع angular.injector مباشرةً، وعليك تمرير وسيط وحيدٍ إليه هو مصفوفةٌ فيها أسماء الوحدات التي ترغب بالبحث ضمنها، ويجب عليك تمرير اسم الوحدة ng دومًا وجعلها في بداية القائمة. var require = function(name) { return angular.injector(['ng','app']).get(name); }; angular.module('app') .controller('LocaleController', ['$scope', function($scope) { var $locale = require('$locale'); $scope.locale = $locale.id; }]);الناتج: Your locale is en-usلاحظ أنّ المثال لايزال يعتمد على حقن التّبعيّة في تمرير كائن المجال الصّحيح للمتحكّم، سأسعى في الفقرة القادمة لأبيّن لك أحد أهمّ المشاكل العمليّة مع الحواشي في الأنظمة الضّخمة، وذلك خشية أن يتبادر إلى ذهنك بأنّ الاستثناء الّذي واجهناه للتّو يلغي الحاجة إلى تبنّي طريقة محدّد موضع الخدمة. مخاطرالمثال التّالي سيستبق الأحداث، ويأخذنا إلى الفصل القادم، الخدمات. سنستخدم في هذا المثال التّابع factory، ورغم أنّك لم تألف استخدامه من قبل إلّا أنّه بإمكانك تخمين وظيفته، فهو يقوم بإعداد مصنعٍ للمكوّن باستخدام نظام الوحدات. لاحظ أيضًا أنّ الخدمة http$ (التي سنناقشها في فصلٍ لاحق HTTP) ستكون خدمةً نموذجيّةً ومثالًا من الحياة العمليّة لاستخدام حقن التّبعيّة داخل خدماتٍ كهذه. angular.module('app') .factory('fullPrice', ['$http', function($http) { return function() { // Use $http to fetch remote data. return 100; } }]) .factory('discountPrice', ['$http', function($http) { return function() { // Use $http to fetch remote data. return 40; } }]);استلهمتُ المثال التّالي من تطبيق Angular حقيقيّ، حيث استُبدلت التّبعيّات بقائمةً طويلةً من الخدمات المدمجة في Angular، ولكنّ طول القائمة هو نفسه تقريبًا. angular.module('app') .controller('PriceController', ['$scope', '$anchorScroll', '$animate', '$cacheFactory', '$compile', '$controller', '$document', '$exceptionHandler', '$filter', '$http', '$httpBackend', '$interpolate', '$interval', 'fullPrice', 'discountPrice', '$locale', '$location', '$log', '$parse', '$q', '$rootElement', '$rootScope', '$sce', '$sceDelegate', '$templateCache', '$timeout', '$window', function( $scope, $anchorScroll, $animate, $cacheFactory, $compile, $controller, $document, $exceptionHandler, $filter, $http, $httpBackend, $interpolate, $interval, discountPrice, fullPrice, $locale, $location, $log, $parse, $q, $rootElement, $rootScope, $sce, $sceDelegate, $templateCache, $timeout, $window) { $scope.fullPrice = fullPrice(); $scope.discountPrice = discountPrice(); }]);من الواضح أنني اختصرت جسم المتحكّم PriceController وكذلك اختصرت شيفرة العرض التّالية. <table ng-controller="PriceController"> <tr> <td>Full price:</td> <td>{{fullPrice}}</td> </tr> <tr> <td>Discount price:</td> <td>{{discountPrice}}</td> </tr> </table>الناتج: Full price: 40 Discount price: 100لقد تعمّدت القيام بخطأٍ في المثال السابق، فالمفترض أن يكون السعر الكلّي أكبر دومًا من السّعر المخفّض، ولكنّهما انعكسا لسببٍ ما، والمشكلة ليست في شيفرة العرض أو في جسم المتحكّم، هل يمكنك إيجادها؟ ماذا تستنتج من ذلك بخصوص كتابة حاشية التّبعيّات يدويًّا في المشاريع الحقيقيّة؟ خاتمةهذا هو الفصل الثّاني من أصل ثلاثة فصول في هذه السلسلة تغطّي البنية التّحتيّة لـAngular الخاصّة بإدارة شيفرة التّطبيق. الفصل الأوّل، الوحدات، بيّنَ كيف سنقوم بتهيئة خشبة المسرح الّتي سيقف عليها الممثّلون ليقوم كلٌّ منهم بدوره. وفي هذا الفصل شرحنا ببعض التّفصيل الآليّات المتاحة لجعل كلِّ ممثّلٍ يقفُ في مكانه الصّحيح. أمّا الفصل الثّالث ضمن هذا المجال، الخدمات، سيشرح كيفيّة إنشاء الممثّلين أنفسهم. ترجمة وبتصرّف للفصل السابع من كتاب: Angular Basics لصاحبه: Chris Smith.
-
- 1
-
- locale
- ng-annotate
-
(و 5 أكثر)
موسوم في: