diff --git a/1-js/01-getting-started/1-intro/article.md b/1-js/01-getting-started/1-intro/article.md index 9f1a27f17..e8044f337 100644 --- a/1-js/01-getting-started/1-intro/article.md +++ b/1-js/01-getting-started/1-intro/article.md @@ -1,6 +1,10 @@ # مقدّمة للجافاسكربت +<<<<<<< HEAD دعونا نرى ما يميز الجافاسكريبت ، وما يمكننا تحقيقه بها ، وأي التقنيات الأخرى التي تعمل بشكل جيد معها. +======= +Let's see what's so special about JavaScript, what we can achieve with it, and what other technologies play well with it. +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a ## ماهي الجافاسكربت؟ @@ -28,7 +32,13 @@ - [سبايدر مونكي](https://ar.wikipedia.org/wiki/سبايدر_مونكي_(محرك_جافا_سكريبت)) -- في فايرفوكس. - ...هناك أسماء رمزية أخرى مثل "تريدانت" و "تشاكرا" لاصدارات مختلفه من انترنت اكسبلورر، "تشاكرا كور" لمايكروسوفت إيدج، "نيترو" و "سكيرلفيش" لسفاري، إلخ. +<<<<<<< HEAD من الجيد تذكر المصطلحات الواردة أعلاه لأنها مستخدمة في مقالات المطورين على الإنترنت. سنستخدمهم أيضًا. على سبيل المثال ، إذا كانت "الميزة إكس مدعومة بواسطة في8" ، فمن المحتمل أنها تعمل في كروم و أوبرا. +======= +- [V8](https://en.wikipedia.org/wiki/V8_(JavaScript_engine)) -- in Chrome and Opera. +- [SpiderMonkey](https://en.wikipedia.org/wiki/SpiderMonkey) -- in Firefox. +- ...There are other codenames like "Chakra" for IE, "ChakraCore" for Microsoft Edge, "Nitro" and "SquirrelFish" for Safari, etc. +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a ```smart header="كيف تعمل المحركات؟" @@ -110,15 +120,30 @@ أمثلة على هذه اللغات: +<<<<<<< HEAD - [كوفي سكريبت](http://coffeescript.org/) هو "سكر نحوي" لجافا سكريبت. إنه يقدم بناء جمل أقصر ، مما يسمح لنا بكتابة كود أكثر وضوحًا ودقة. عادة ،مطورو الروبي يحبونها. - يركز [تايب سكريبت](http://www.typescriptlang.org/) على إضافة "كتابة بيانات صارمة" لتبسيط تطوير ودعم الأنظمة المعقدة. تم تطويره بواسطة ميكروسوفت. - يضيف [فلاو](http://flow.org/) أيضًا كتابة البيانات ، ولكن بطريقة مختلفة. تم تطويره بواسطة فايسبوك. - [دارت](https://www.dartlang.org/) هي لغة قائمة بذاتها لها محركها الخاص الذي يعمل في بيئات غير المتصفح (مثل تطبيقات الهاتف المحمول) ، ولكن يمكن أيضًا تحويلها إلى جافاسكريبت. من تطوير جوجل. +======= +- [CoffeeScript](http://coffeescript.org/) is a "syntactic sugar" for JavaScript. It introduces shorter syntax, allowing us to write clearer and more precise code. Usually, Ruby devs like it. +- [TypeScript](http://www.typescriptlang.org/) is concentrated on adding "strict data typing" to simplify the development and support of complex systems. It is developed by Microsoft. +- [Flow](http://flow.org/) also adds data typing, but in a different way. Developed by Facebook. +- [Dart](https://www.dartlang.org/) is a standalone language that has its own engine that runs in non-browser environments (like mobile apps), but also can be transpiled to JavaScript. Developed by Google. +- [Brython](https://brython.info/) is a Python transpiler to JavaScript that enables the writing of applications in pure Python without JavaScript. +- [Kotlin](https://kotlinlang.org/docs/reference/js-overview.html) is a modern, concise and safe programming language that can target the browser or Node. +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a هناك أكثر. بالطبع ، حتى لو استخدمنا إحدى اللغات المترجمة ، يجب أن نعرف أيضًا جافاسكريبت لفهم ما نقوم به حقًا. ## ملخص +<<<<<<< HEAD - تم إنشاء الجافاسكريبت في البداية كلغة للمتصفح فقط ، ولكنها تُستخدم الآن في العديد من البيئات الأخرى أيضًا. - تتمتع جافاسكريبت اليوم بمكانة فريدة باعتبارها لغة المتصفح الأكثر استخدامًا مع تكاملها التام مع HTML / CSS. - هناك العديد من اللغات التي يتم "تحويلها" إلى الجافاسكريبت وتوفر ميزات معينة. يوصى بإلقاء نظرة عليهم ، على الأقل لفترة وجيزة ، بعد إتقان الجافاسكريبت. +======= +- JavaScript was initially created as a browser-only language, but it is now used in many other environments as well. +- Today, JavaScript has a unique position as the most widely-adopted browser language with full integration in HTML/CSS. +- There are many languages that get "transpiled" to JavaScript and provide certain features. It is recommended to take a look at them, at least briefly, after mastering JavaScript. +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a diff --git a/1-js/01-getting-started/2-manuals-specifications/article.md b/1-js/01-getting-started/2-manuals-specifications/article.md index 12850480d..96a635209 100644 --- a/1-js/01-getting-started/2-manuals-specifications/article.md +++ b/1-js/01-getting-started/2-manuals-specifications/article.md @@ -14,14 +14,23 @@ أيضاً، إذا كنت تطور من أجل المتصفح، إذا هناك مواصفات أخرى مشمولة في [الجزء الثاني](info:browser-environment) من الدورة التعليمية. +<<<<<<< HEAD ## المراجع +======= +Also, if you're in developing for the browser, then there are other specifications covered in the [second part](info:browser-environment) of the tutorial. +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a - **MDN (Mozilla) JavaScript Reference** هذا دليل بأمثلة ومعلومات أخرى. وهو مصدر جيد للحصول على معلومات تفصيلية حول ميزات اللغة، وطرق الكائنات المضمنة، وما إلى ذلك. +<<<<<<< HEAD يمكن أن تجدها في . +======= +- **MDN (Mozilla) JavaScript Reference** is the main manual with examples and other information. It's great to get in-depth information about individual language functions, methods etc. +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a أيضاً، غالباً ما يكون من الأفضل استخدام البحث عبر الإنترنت بدلاً من ذلك. فقط استخدم "[مصطلح] MDN" للإستعلام، مثال لتبحث عن دالة `parseInt`. +<<<<<<< HEAD * **MSDN** – مراجع ميكروسوفت يوجد بها معلومات كثيرة، متضمنة جافاسكريبت (غالباً يشار إليها JScript). إذا كنت تريد شيئا أكثر تخصصا عن انترنت اكسبلورر، من الأفضل الذهاب إلى: . أيضاً، يمكن غن نستخدم بحث الإنترنت بعبارات مثل "RegExp MSDN" or "RegExp MSDN jscript". @@ -29,6 +38,9 @@ ## جدول التوافق جافاسكريبت لغة فى سياق متطور، تضاف إليها خصائص جديدة بانتظام. +======= +Although, it's often best to use an internet search instead. Just use "MDN [term]" in the query, e.g. to search for `parseInt` function. +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a لتَّـحَقّـق من الدعم ما بين المتصفحات والمحركات الأخرى، انظر: diff --git a/1-js/01-getting-started/4-devtools/article.md b/1-js/01-getting-started/4-devtools/article.md index 89c37efdc..e765fdeb8 100644 --- a/1-js/01-getting-started/4-devtools/article.md +++ b/1-js/01-getting-started/4-devtools/article.md @@ -11,9 +11,13 @@ اضغط على F12 (أو الاختصار Cmd+Opt+J إذا كنت تستخدم نظام التشغيل «ماك») وسيفتح ذلك تلقائيًا أدوات المطوّر على لسان «الطرفية» (Console). وتظهر أدوات المطوّر تقريبًا بهذا الشكل: +<<<<<<< HEAD يعتمد شكل أدوات المطوّر على إصدار متصفِّح Chrome الذي تستخدمه، إذ يختلف بشكل بسيط من إصدار إلى آخر. - بإمكانك رؤية رسالة الخطأ باللون الأحمر. معنى الرسالة أن السكربت يحتوي على أمر غير معروف هو "lalala". - لاحظ في أقصى اليمين وجود رابط إلى المصدر bug.html:12 مع رقم سطر الخطأ في الشيفرة. +======= +Developer tools are potent, they have many features. To start, we'll learn how to open them, look at errors, and run JavaScript commands. +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a يظهر تحت رسالة الخطأ الرمز `<` باللون الأزرق، ويحدد «سطر الأوامر» (command line) الذي سنكتب عنده أوامر وتعليمات JavaScript. اضغط زر الإدخال Enter لتنفيذ الأمر بعد كتابته (أو Shift+Enter للانتقال إلى السطر التالي عند إدخال أمر متعدد الأسطر). diff --git a/1-js/02-first-steps/01-hello-world/article.md b/1-js/02-first-steps/01-hello-world/article.md index c23e69584..d399b8b0a 100644 --- a/1-js/02-first-steps/01-hello-world/article.md +++ b/1-js/02-first-steps/01-hello-world/article.md @@ -9,7 +9,11 @@ ## الوسم "script" +<<<<<<< HEAD يمكن وضع برامج الجافاسكريبت في أي جزء في مستند HTML باستخدام وسم ` diff --git a/1-js/13-modules/02-import-export/article.md b/1-js/13-modules/02-import-export/article.md index e5f9a856c..4463111b1 100644 --- a/1-js/13-modules/02-import-export/article.md +++ b/1-js/13-modules/02-import-export/article.md @@ -317,7 +317,11 @@ export {default as User} from './user.js'; // نُعيد تصدير المبدئ ولكن فيمَ نستعمل هذا أصلًا؟ لنرى مثالًا عمليًا. +<<<<<<< HEAD لنقل بأننا نكتب ”حزمة“، أي مجلدًا فيه وحدات كثيرة وأردنا تصدير بعض ميزاتها إلى الخارج (تتيح لنا الأدوات مثل NPM نشر هذه الحزم وتوزيعها)، ونعلم أيضًا أن الكثير من وحداتها ما هي إلّا وحدات مُساعِدة +======= +Imagine, we're writing a "package": a folder with a lot of modules, with some of the functionality exported outside (tools like NPM allow us to publish and distribute such packages, but we don't have to use them), and many modules are just "helpers", for internal use in other package modules. +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a يمكن أن تكون بنية الملفات هكذا: ``` @@ -374,7 +378,11 @@ export {default as User} from './user.js'; يحتاج التصدير المبدئي لمعالجة منفصلة عند إعادة التصدير. +<<<<<<< HEAD لنفترض أن لدينا `user.js`، ونود إعادة تصدير الصنف ` User` منه: +======= +Let's say we have `user.js` with the `export default class User` and would like to re-export it: +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a ``` // 📁 user.js @@ -384,7 +392,13 @@ export default class User { ``` 1. لن تعمل التعليمة `export User from './user.js'‎`. ما الخطأ الذي حدث؟ ولكن هذا الخطأ في صياغة! +<<<<<<< HEAD لإعادة تصدير الملفات المصدرة إفتراضيًا ، علينا كتابة `export {default as User}‎` ، كما في المثال أعلاه. +======= +We can come across two problems with it: + +1. `export User from './user.js'` won't work. That would lead to a syntax error. +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a 2. تعيد التعليمة `export * from './user.js'‎` تصدير التصديرات الّتي لها أسماء فقط، ولكنها تتجاهل التصديرات المبدئية. @@ -394,8 +408,12 @@ export default class User { export * from './user.js'; // لإعادة تصدير التصديرات الّتي لها أسماء export {default} from './user.js'; // لإعادة تصدير التصديرات المبدئية +<<<<<<< HEAD ``` هذه الغرابة في طريقة إعادة تصدير التصديرات المبدئية هي من أحد الأسباب لجعل بعض المطورين لا يحبونها. +======= +Such oddities of re-exporting a default export are one of the reasons why some developers don't like default exports and prefer named ones. +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a ## خلاصة diff --git a/1-js/99-js-misc/01-proxy/01-error-nonexisting/solution.md b/1-js/99-js-misc/01-proxy/01-error-nonexisting/solution.md index 357a57313..9db69cb2f 100644 --- a/1-js/99-js-misc/01-proxy/01-error-nonexisting/solution.md +++ b/1-js/99-js-misc/01-proxy/01-error-nonexisting/solution.md @@ -19,5 +19,5 @@ function wrap(target) { user = wrap(user); alert(user.name); // John -alert(user.age); // ReferenceError: Property doesn't exist "age" +alert(user.age); // ReferenceError: Property doesn't exist: "age" ``` diff --git a/1-js/99-js-misc/01-proxy/01-error-nonexisting/task.md b/1-js/99-js-misc/01-proxy/01-error-nonexisting/task.md index fd0265f01..36c6b4124 100644 --- a/1-js/99-js-misc/01-proxy/01-error-nonexisting/task.md +++ b/1-js/99-js-misc/01-proxy/01-error-nonexisting/task.md @@ -1,8 +1,16 @@ +<<<<<<< HEAD # خطأ عند قراءة خاصية غير موجودة عادة، عند محاولة قراءة خاصية غير موجودة فإنها تُرجع `undefined`. قم بإنشاء بروكسي يقوم بإظهار خطأ عند محاولة قراءة خاصية غير موجودة بدلًا من ذلك. +======= +# Error on reading non-existent property + +Usually, an attempt to read a non-existent property returns `undefined`. + +Create a proxy that throws an error for an attempt to read of a non-existent property instead. +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a هذا يساعد علي استكشاف الأخطاء البرمجية بشكل أسرع. @@ -27,6 +35,6 @@ user = wrap(user); alert(user.name); // John *!* -alert(user.age); // ReferenceError: Property doesn't exist "age" +alert(user.age); // ReferenceError: Property doesn't exist: "age" */!* ``` diff --git a/1-js/99-js-misc/01-proxy/article.md b/1-js/99-js-misc/01-proxy/article.md index 3c4c19d28..dbec2edb2 100644 --- a/1-js/99-js-misc/01-proxy/article.md +++ b/1-js/99-js-misc/01-proxy/article.md @@ -53,6 +53,7 @@ for (let key in proxy) alert(key); // test, التكرار يعمل (3) لكل دالة داخلية يوجد trap في هذا الجدول: اسم الدالة التي يمكننا إضافتها للمتغير الذي يسمي `handler` والذي نضيفه للـ `new Proxy` للتدخل فى العملية: +<<<<<<< HEAD | الدالة الداخلية | الدالة العاملة | تعمل عند... | | ----------------------- | -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `[[Get]]` | `get` | قراءة خاصية | @@ -68,6 +69,23 @@ for (let key in proxy) alert(key); // test, التكرار يعمل (3) | `[[DefineOwnProperty]]` | `defineProperty` | [Object.defineProperty](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty), [Object.defineProperties](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperties) | | `[[GetOwnProperty]]` | `getOwnPropertyDescriptor` | [Object.getOwnPropertyDescriptor](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/getOwnPropertyDescriptor), `for..in`, `Object.keys/values/entries` | | `[[OwnPropertyKeys]]` | `ownKeys` | [Object.getOwnPropertyNames](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/getOwnPropertyNames), [Object.getOwnPropertySymbols](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/getOwnPropertySymbols), `for..in`, `Object/keys/values/entries` | +======= +| Internal Method | Handler Method | Triggers when... | +|-----------------|----------------|-------------| +| `[[Get]]` | `get` | reading a property | +| `[[Set]]` | `set` | writing to a property | +| `[[HasProperty]]` | `has` | `in` operator | +| `[[Delete]]` | `deleteProperty` | `delete` operator | +| `[[Call]]` | `apply` | function call | +| `[[Construct]]` | `construct` | `new` operator | +| `[[GetPrototypeOf]]` | `getPrototypeOf` | [Object.getPrototypeOf](mdn:/JavaScript/Reference/Global_Objects/Object/getPrototypeOf) | +| `[[SetPrototypeOf]]` | `setPrototypeOf` | [Object.setPrototypeOf](mdn:/JavaScript/Reference/Global_Objects/Object/setPrototypeOf) | +| `[[IsExtensible]]` | `isExtensible` | [Object.isExtensible](mdn:/JavaScript/Reference/Global_Objects/Object/isExtensible) | +| `[[PreventExtensions]]` | `preventExtensions` | [Object.preventExtensions](mdn:/JavaScript/Reference/Global_Objects/Object/preventExtensions) | +| `[[DefineOwnProperty]]` | `defineProperty` | [Object.defineProperty](mdn:/JavaScript/Reference/Global_Objects/Object/defineProperty), [Object.defineProperties](mdn:/JavaScript/Reference/Global_Objects/Object/defineProperties) | +| `[[GetOwnProperty]]` | `getOwnPropertyDescriptor` | [Object.getOwnPropertyDescriptor](mdn:/JavaScript/Reference/Global_Objects/Object/getOwnPropertyDescriptor), `for..in`, `Object.keys/values/entries` | +| `[[OwnPropertyKeys]]` | `ownKeys` | [Object.getOwnPropertyNames](mdn:/JavaScript/Reference/Global_Objects/Object/getOwnPropertyNames), [Object.getOwnPropertySymbols](mdn:/JavaScript/Reference/Global_Objects/Object/getOwnPropertySymbols), `for..in`, `Object.keys/values/entries` | +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a ```warn header="بعض الثوابت" تفرض الجافاسكريبت بعض الثوابت -- شروط يجب أن تتحقق بالmethods و الtraps. @@ -378,7 +396,11 @@ user = new Proxy(user, { } }, *!* +<<<<<<< HEAD deleteProperty(target, prop) { // لاعتراض حذف الخاصية +======= + deleteProperty(target, prop) { // to intercept property deletion +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a */!* if (prop.startsWith('_')) { throw new Error("Access denied"); @@ -441,7 +463,13 @@ user = { استدعاء `user.checkPassword()` يقوم بإرجاع `user` المُحاط ببروكسي كقيمة لـ `this` (الأوبجكت قبل علامة النقطة هو قيمة `this`)، ولذلك فعندما تحاول الوصول إلي `this._password` ينشط الـtrap `get` (تعمل مع كل استدعاء لخاصية) وتظهر خطأًا. +<<<<<<< HEAD ولذلك نقوم بربط سياق دوال الأوبجكت بالأوبجكت الأصلي، `target`، في لاسطر `(*)`. وبعد ذلك فإن استدعائهم في المستقبل سيسختدم `target` كقيمة لـ `this`، بدون trap. +======= +A call to `user.checkPassword()` gets proxied `user` as `this` (the object before dot becomes `this`), so when it tries to access `this._password`, the `get` trap activates (it triggers on any property read) and throws an error. + +So we bind the context of object methods to the original object, `target`, in the line `(*)`. Then their future calls will use `target` as `this`, without any traps. +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a هذا الحل عادة ما يعمل، ولكنه ليس مثاليًا، فإن دالة كهذه يمكنها أن ترجع الأوبجكت غير محاط ببروكسي في أي مكان آخر وهكذا سيفسد كل شيئ: أين الأوبجكت الأصلي؟ وأين المحاط ببروكسي؟ @@ -843,7 +871,11 @@ alert(proxy.get('test')); // 1 (works!) ### الخصائص الخاصة Private fields +<<<<<<< HEAD الشيئ المشابه يحدث مع الخصائص الخاصة بالكلاس. +======= +A similar thing happens with private class fields. +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a علي سبيل المثال، الدالة `getName()` تصل إلي الخاصية الخاصة `#name` وتقف بعد الإحاطة: @@ -965,9 +997,19 @@ revoke(); alert(proxy.data); // خطأ ``` +<<<<<<< HEAD استدعاء `revoke()` يمسح كل المراجع الداخلية للأوبجكت المستهدف من البروكسي، ولذلك فإنهما ليسا متصلان بعد الآن. الأوبجكت المستهدف يمكن أن يتم تنظيفه بعد ذلك. يمكننا أيضًا أن نخزن الدالة `revoke` في `WeakMap`، لنكون قادرين علي إيجاده بواسطة بروكسي: +======= +A call to `revoke()` removes all internal references to the target object from the proxy, so they are no longer connected. + +Initially, `revoke` is separate from `proxy`, so that we can pass `proxy` around while leaving `revoke` in the current scope. + +We can also bind `revoke` method to proxy by setting `proxy.revoke = revoke`. + +Another option is to create a `WeakMap` that has `proxy` as the key and the corresponding `revoke` as the value, that allows to easily find `revoke` for a proxy: +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a ```js run *!* @@ -982,21 +1024,30 @@ let {proxy, revoke} = Proxy.revocable(object, {}); revokes.set(proxy, revoke); -// ..later in our code.. +// ..somewhere else in our code.. revoke = revokes.get(proxy); revoke(); alert(proxy.data); // خطأ (تم إلغاؤه) ``` +<<<<<<< HEAD الفائدة من نهج كهذا هو أننا لسنا مضطرين لأن نحمل الدالة `revoke`. يمكننا الحصول عليها من الmap بواسطة `proxy` عند الحاجه. نستخدم `WeakMap` بدلًل من `Map`هنا لأننا لا نريد أن نمنع عملية التنظيف (garbage collection). إذا أصبح الأوبجكت "لا يمكن الوصول إليه" (علي سبيل المثال لا توجد أي متغيرات تصل إليها)، تسمح له الـ `WeakMap` أن يتم مسحه من الذاكرة مع دالة `revoke` الخاصة به فليس هناك حاجة لها بعد الآن. +======= +We use `WeakMap` instead of `Map` here because it won't block garbage collection. If a proxy object becomes "unreachable" (e.g. no variable references it any more), `WeakMap` allows it to be wiped from memory together with its `revoke` that we won't need any more. +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a ## المراجع +<<<<<<< HEAD - المصدر: [Proxy](https://tc39.es/ecma262/#sec-proxy-object-internal-methods-and-internal-slots). - MDN: [Proxy](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy). +======= +- Specification: [Proxy](https://tc39.es/ecma262/#sec-proxy-object-internal-methods-and-internal-slots). +- MDN: [Proxy](mdn:/JavaScript/Reference/Global_Objects/Proxy). +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a ## الملخص @@ -1016,16 +1067,28 @@ let proxy = new Proxy(target, { يمكننا أن نعترض: +<<<<<<< HEAD - قراءة (`get`), تعديل (`set`), حذف (`deleteProperty`) خاصية (حتي إذا لم تكن موجودة). - استدعاء دالة (`apply`). - المعامل `new` (`construct` trap). - وغيره الكثير من العمليات (القامة الكاملة موجودة في بداية المقال وفي [المصدر](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy)). +======= +We can trap: +- Reading (`get`), writing (`set`), deleting (`deleteProperty`) a property (even a non-existing one). +- Calling a function (`apply` trap). +- The `new` operator (`construct` trap). +- Many other operations (the full list is at the beginning of the article and in the [docs](mdn:/JavaScript/Reference/Global_Objects/Proxy)). +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a هذا يسمح لنا أن ننشئ خواص ودوال افتراضية واسترجاع قيم افتراضية وأوبجكت ملحوظ والكثير. يمكننا أيضًا أن نعترض أوبجكت مرات عدة ببروكسي مختلف، وتعليمها بطرق مختلفة. +<<<<<<< HEAD [الكائن Reflect](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect) تم إنشاؤه ليكمل الـ [Proxy](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy). لكل trap في `Proxy`, يوجد استدعاء لـ `Reflect` بنفس المتغيرات. يجب أن نستخدمها لتمرير القيم إلي الأوبجكت المستهدف. +======= +The [Reflect](mdn:/JavaScript/Reference/Global_Objects/Reflect) API is designed to complement [Proxy](mdn:/JavaScript/Reference/Global_Objects/Proxy). For any `Proxy` trap, there's a `Reflect` call with same arguments. We should use those to forward calls to target objects. +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a البروكسي له حدود: diff --git a/1-js/99-js-misc/03-currying-partials/article.md b/1-js/99-js-misc/03-currying-partials/article.md index 2430c3372..84de14914 100644 --- a/1-js/99-js-misc/03-currying-partials/article.md +++ b/1-js/99-js-misc/03-currying-partials/article.md @@ -147,7 +147,7 @@ function curried(...args) { if (args.length >= func.length) { // (1) return func.apply(this, args); } else { - return function pass(...args2) { // (2) + return function(...args2) { // (2) return curried.apply(this, args.concat(args2)); } } @@ -156,6 +156,7 @@ function curried(...args) { عند تشغيله، هناك فرعين للتنفيذ من الجملة الشرطية `if`: +<<<<<<< HEAD 1. سيكون الاستدعاء الآن هكذا: إن كان عدد الوسطاء `args` المُمرّرة هو نفس العدد الدالة الأصليّة المعرّفة لدينا (`func.length`) أو أكثر، عندها نمرّر الاستدعاء له فقط. 2. وإلا سيكون الاستدعاء جزئيًا: لم تُستدعى الدالّة `func` بعد. وإنما أعيد بدلًا منها دالّة المغلِّفة أخرى `pass`، والتي ستُعيد تطبيق الدالة `curried` مع تقديم الوسطاء السابقين مع الوسطاء الجدد. وثمّ في استدعاء الجديد سنحصل إما على دالة جزئية جديدة (إن لم يكُ عدد الوسطاء كافيا) أو النتيجة النهائية. @@ -169,6 +170,12 @@ function curried(...args) { إذا لم تتوضح الفكرة حتى الآن، فما عليك إلا تتبع تسلسل الاستدعاءات في عقلك أو على الورقة وستتوضح الأمور أكثر. **ملاحظة**: تعمل مع الدوالّ ثابتة الطول فقط +======= +1. If passed `args` count is the same or more than the original function has in its definition (`func.length`) , then just pass the call to it using `func.apply`. +2. Otherwise, get a partial: we don't call `func` just yet. Instead, another wrapper is returned, that will re-apply `curried` providing previous arguments together with the new ones. + +Then, if we call it, again, we'll get either a new partial (if not enough arguments) or, finally, the result. +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a يجب أن يكون للدالّة عدد ثابت من الوسطاء لتطبيق تقنية currying. diff --git a/1-js/99-js-misc/04-reference-type/3-why-this/solution.md b/1-js/99-js-misc/04-reference-type/3-why-this/solution.md index 7b74d89ae..9a2c67758 100644 --- a/1-js/99-js-misc/04-reference-type/3-why-this/solution.md +++ b/1-js/99-js-misc/04-reference-type/3-why-this/solution.md @@ -5,7 +5,11 @@ 2. نفس الشيء ، الأقواس لا تغير ترتيب العمليات هنا ، النقطة أولاً على أي حال. +<<<<<<< HEAD 3. هنا لدينا تنفيذ اكثر تعقيداً `(expression).method()`. التنفيذ يعمل كما لو كان مقسوم الى سطرين: +======= +3. Here we have a more complex call `(expression)()`. The call works as if it were split into two lines: +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a ```js no-beautify f = obj.go; // حساب المصطلح @@ -14,7 +18,11 @@ هنا `f()` يتم تنفيذها كـ تابع, بدون `this`. +<<<<<<< HEAD 4. نفس الشيئ في `(3)`, ايسر النقطة `.` لدينا مصطلح. +======= +4. The similar thing as `(3)`, to the left of the parentheses `()` we have an expression. +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a لتفسير سلوك `(3)` و `(4)` نريد إعادة تنفيذ مدخلات الخاصية (نقطة او اقواس مربعة) تعيد قيمة النوع المرجعي. diff --git a/1-js/99-js-misc/04-reference-type/article.md b/1-js/99-js-misc/04-reference-type/article.md index 87aa90109..d4643f2c1 100644 --- a/1-js/99-js-misc/04-reference-type/article.md +++ b/1-js/99-js-misc/04-reference-type/article.md @@ -93,7 +93,11 @@ hi(); // خطأ, لأن this غير معرفة اى عملية اخري مثل `hi = user.hi` تتجاهل النوع المرجعي بالكامل, تأخذ القيمة من `user.hi` (التابع) و تقوم بتمريره. اذا اى من العمليات المستقبلية "تفقد" `this`. +<<<<<<< HEAD لذا, قيمة `this` يتم تمريرها بالطريقة الصحيحة فقط إذا تم استدعاء التابع مباشرةً باستخدام نقطة `obj.method()` أو الاقواس المربعة `obj['method']()` (يقومون بنفس الوظيفه هنا). لاحقًا في هذا البرنامج التعليمي ، سنتعلم طرقًا مختلفة لحل هذه المشكلة مثل [func.bind()](/bind#solution-2-bind). +======= +So, as the result, the value of `this` is only passed the right way if the function is called directly using a dot `obj.method()` or square brackets `obj['method']()` syntax (they do the same here). There are various ways to solve this problem such as [func.bind()](/bind#solution-2-bind). +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a ## الملخص @@ -105,6 +109,7 @@ hi(); // خطأ, لأن this غير معرفة بالنسبة لجميع العمليات الأخرى ، يصبح النوع المرجعي تلقائيًا قيمة الخاصية (تابع في حالتنا). +<<<<<<< HEAD جميع آليات العمل مختفيه. لا يهم إلا في الحالات الدقيقة, مثل عندما يتم الحصول على طريقة ديناميكيًا من الكائن ، باستخدام تعبير. @@ -112,3 +117,6 @@ hi(); // خطأ, لأن this غير معرفة نتيجة النقطة `.` ليست في الواقع طريقة ، ولكنها قيمة `` يحتاج إلى طريقة لتمرير المعلومات حول `obj` +======= +The whole mechanics is hidden from our eyes. It only matters in subtle cases, such as when a method is obtained dynamically from the object, using an expression. +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a diff --git a/1-js/99-js-misc/05-bigint/article.md b/1-js/99-js-misc/05-bigint/article.md index 4c43353e4..893d168e8 100644 --- a/1-js/99-js-misc/05-bigint/article.md +++ b/1-js/99-js-misc/05-bigint/article.md @@ -50,7 +50,11 @@ alert(Number(bigint) + number); // 3 ````smart header="لا يتم دعم ميزة الزائد الأحادي (+) على `bigints`" يعد عامل تشغيل الزائد الأحادي `+value` طريقة معروفة لتحويل `value` إلى رقم. +<<<<<<< HEAD لا يتم دعم عامل التشغيل هذا عند العمل مع أرقام `BigInt`: +======= +In order to avoid confusion, it's not supported on bigints: +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a ```js run let bigint = 1n; @@ -130,5 +134,10 @@ alert( 0n || 2 ); // 2 (0n ستكون `false`) ## المراجع +<<<<<<< HEAD - [MDN BigInt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt). - [تخصيص](https://tc39.es/ecma262/#sec-bigint-objects). +======= +- [MDN docs on BigInt](mdn:/JavaScript/Reference/Global_Objects/BigInt). +- [Specification](https://tc39.es/ecma262/#sec-bigint-objects). +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a diff --git a/2-ui/1-document/02-dom-nodes/article.md b/2-ui/1-document/02-dom-nodes/article.md index 24e209034..e532dffac 100644 --- a/2-ui/1-document/02-dom-nodes/article.md +++ b/2-ui/1-document/02-dom-nodes/article.md @@ -51,7 +51,7 @@ setTimeout(() => document.body.style.background = '', 3000); // لإزالة ا
@@ -142,8 +142,13 @@ let node4 = {"name":"HTML","nodeType":1,"children":[{"name":"HEAD","nodeType":1, drawHtmlTree(node4, 'div.domtree', 690, 360); +<<<<<<< HEAD ````warn header="الجدأول دائما ما تحتوي على ``" تُشكل الجدأول "حالة خاصة" مُثيرة للإهتمام. وفقا لمواصفات نموذج كائن المستند، ينبغي أن يكون لدى الجدأول علامة ``، ولكنها قد تكون محذوفة من HTML (الرسمي). ويقوم المتصفح لاحقا بإنشاء `` تلقائيا في نموذج كائن المستند. +======= +````warn header="Tables always have ``" +An interesting "special case" is tables. By DOM specification they must have `` tag, but HTML text may omit it. Then the browser creates `` in the DOM automatically. +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a ملف HTML: @@ -160,7 +165,11 @@ let node5 = {"name":"TABLE","nodeType":1,"children":[{"name":"TBODY","nodeType": drawHtmlTree(node5, 'div.domtree', 600, 200); +<<<<<<< HEAD أترى؟ لقد وُجدت علامة `` من العدم. يجب أن تضع هذا في الاعتبار أثناء العمل مع الجدأول لتجنب المفاجآت. +======= +You see? The `` appeared out of nowhere. We should keep this in mind while working with tables to avoid surprises. +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a ```` ## أنواع العقد الأخرى @@ -188,7 +197,11 @@ drawHtmlTree(node5, 'div.domtree', 600, 200);
@@ -199,7 +212,11 @@ drawHtmlTree(node6, 'div.domtree', 690, 500); **كل شيء في HTML، حتى التعليقات، تصبح جزءا من نموذج كائن المستند.** +<<<<<<< HEAD حتى تعليمة `` في بداية HTML هي أيضا عقدة من نموذج كائن المستند. فهي توجد في شجرة نموذج كائن المستند قبل `` مباشرة. لن نتعامل مع تلك العقدة، حتى أنها لا تُرسم على الرسوم البيانية لهذا السبب، ولكنها موجودة. +======= +Even the `` directive at the very beginning of HTML is also a DOM node. It's in the DOM tree right before ``. Few people know about that. We are not going to touch that node, we even don't draw it on diagrams, but it's there. +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a كائن `المستند`، والذي يُمثل المستند بأكمله، يُكون عقدة من نموذج كائن المستند أيضا. diff --git a/2-ui/1-document/04-searching-elements-dom/article.md b/2-ui/1-document/04-searching-elements-dom/article.md index f5ab0b785..5af6435ce 100644 --- a/2-ui/1-document/04-searching-elements-dom/article.md +++ b/2-ui/1-document/04-searching-elements-dom/article.md @@ -71,7 +71,7 @@ If there are multiple elements with the same `id`, then the behavior of methods ``` ```warn header="Only `document.getElementById`, not `anyElem.getElementById`" -The method `getElementById` that can be called only on `document` object. It looks for the given `id` in the whole document. +The method `getElementById` can be called only on `document` object. It looks for the given `id` in the whole document. ``` ## querySelectorAll [#querySelectorAll] @@ -142,7 +142,7 @@ For instance: *Ancestors* of an element are: parent, the parent of parent, its parent and so on. The ancestors together form the chain of parents from the element to the top. -The method `elem.closest(css)` looks the nearest ancestor that matches the CSS-selector. The `elem` itself is also included in the search. +The method `elem.closest(css)` looks for the nearest ancestor that matches the CSS-selector. The `elem` itself is also included in the search. In other words, the method `closest` goes up from the element and checks each of parents. If it matches the selector, then the search stops, and the ancestor is returned. @@ -363,7 +363,7 @@ There are 6 main methods to search for nodes in DOM: -By far the most used are `querySelector` and `querySelectorAll`, but `getElementBy*` can be sporadically helpful or found in the old scripts. +By far the most used are `querySelector` and `querySelectorAll`, but `getElement(s)By*` can be sporadically helpful or found in the old scripts. Besides that: diff --git a/2-ui/1-document/05-basic-dom-node-properties/article.md b/2-ui/1-document/05-basic-dom-node-properties/article.md index d94492f4e..2cd3fcf09 100644 --- a/2-ui/1-document/05-basic-dom-node-properties/article.md +++ b/2-ui/1-document/05-basic-dom-node-properties/article.md @@ -197,7 +197,11 @@ alert( document.body instanceof EventTarget ); // true ## innerHTML: المحتويات +<<<<<<< HEAD تتيح خاصية [innerHTML] (https://w3c.github.io/DOM-Parsing/#widl-Element-innerHTML) الحصول على HTML داخل العنصر كسلسلة. +======= +The [innerHTML](https://w3c.github.io/DOM-Parsing/#the-innerhtml-mixin) property allows to get the HTML inside the element as a string. +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a يمكننا أيضًا تعديله. لذا فهي واحدة من أقوى الطرق لتغيير الصفحة. @@ -396,15 +400,20 @@ elem.innerHTML = elem.innerHTML + "..."
``` +<<<<<<< HEAD 1. يحصل الاسم الأول "
" على الاسم "بتنسيق HTML": تصبح جميع العلامات علامات ، لذلك نرى الاسم الغامق. 2. الثانية `
` تحصل على الاسم "كنص" ، لذلك نرى حرفياً " Winnie-the-pooh! `. +======= +1. The first `
` gets the name "as HTML": all tags become tags, so we see the bold name. +2. The second `
` gets the name "as text", so we literally see `Winnie-the-Pooh!`. +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a في معظم الحالات ، نتوقع النص من مستخدم ونريد معاملته كنص. لا نريد HTML غير متوقع في موقعنا. يؤدي التعيين إلى `textContent` ذلك بالضبط. @@ -412,7 +421,11 @@ elem.innerHTML = elem.innerHTML + "..." تحدد السمة "مخفي" وخاصية DOM ما إذا كان العنصر مرئيًا أم لا. +<<<<<<< HEAD يمكننا استخدامه في HTML أو تخصيصه باستخدام JavaScript ، مثل هذا: +======= +We can use it in HTML or assign it using JavaScript, like this: +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a ```html run height="80"
Both divs below are hidden
diff --git a/2-ui/1-document/06-dom-attributes-and-properties/article.md b/2-ui/1-document/06-dom-attributes-and-properties/article.md index ef8ce6c93..196cecbb5 100644 --- a/2-ui/1-document/06-dom-attributes-and-properties/article.md +++ b/2-ui/1-document/06-dom-attributes-and-properties/article.md @@ -298,7 +298,11 @@ document.body.sayHi(); // Hello, I'm BODY
``` +<<<<<<< HEAD لماذا يكون استخدام السمة أفضل من وجود فئات مثل `.order-state-new` و` .order-state-pending` و `order-state-cancell`؟ +======= +Why would using an attribute be preferable to having classes like `.order-state-new`, `.order-state-pending`, `.order-state-canceled`? +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a لأن السمة أكثر ملاءمة للإدارة. يمكن تغيير الحالة بالسهولة التالية: diff --git a/2-ui/1-document/07-modifying-document/10-clock-setinterval/solution.md b/2-ui/1-document/07-modifying-document/10-clock-setinterval/solution.md index 15238fcf4..1414e90c1 100644 --- a/2-ui/1-document/07-modifying-document/10-clock-setinterval/solution.md +++ b/2-ui/1-document/07-modifying-document/10-clock-setinterval/solution.md @@ -39,15 +39,19 @@ The clock-managing functions: ```js let timerId; -function clockStart() { // run the clock - timerId = setInterval(update, 1000); +function clockStart() { // run the clock + if (!timerId) { // only set a new interval if the clock is not running + timerId = setInterval(update, 1000); + } update(); // (*) } function clockStop() { clearInterval(timerId); - timerId = null; + timerId = null; // (**) } ``` Please note that the call to `update()` is not only scheduled in `clockStart()`, but immediately run in the line `(*)`. Otherwise the visitor would have to wait till the first execution of `setInterval`. And the clock would be empty till then. + +Also it is important to set a new interval in `clockStart()` only when the clock is not running. Otherways clicking the start button several times would set multiple concurrent intervals. Even worse - we would only keep the `timerID` of the last interval, losing references to all others. Then we wouldn't be able to stop the clock ever again! Note that we need to clear the `timerID` when the clock is stopped in the line `(**)`, so that it can be started again by running `clockStart()`. diff --git a/2-ui/1-document/07-modifying-document/10-clock-setinterval/solution.view/index.html b/2-ui/1-document/07-modifying-document/10-clock-setinterval/solution.view/index.html index 1bf642b10..de8ec9aee 100644 --- a/2-ui/1-document/07-modifying-document/10-clock-setinterval/solution.view/index.html +++ b/2-ui/1-document/07-modifying-document/10-clock-setinterval/solution.view/index.html @@ -43,12 +43,17 @@ } function clockStart() { - timerId = setInterval(update, 1000); + // set a new interval only if the clock is stopped + // otherwise we would rewrite the timerID reference to the running interval and wouldn't be able to stop the clock ever again + if (!timerId) { + timerId = setInterval(update, 1000); + } update(); // <-- start right now, don't wait 1 second till the first setInterval works } function clockStop() { clearInterval(timerId); + timerId = null; // <-- clear timerID to indicate that the clock has been stopped, so that it is possible to start it again in clockStart() } clockStart(); diff --git a/2-ui/1-document/07-modifying-document/article.md b/2-ui/1-document/07-modifying-document/article.md index 3e0bdea7d..8fd2d4246 100644 --- a/2-ui/1-document/07-modifying-document/article.md +++ b/2-ui/1-document/07-modifying-document/article.md @@ -61,7 +61,7 @@ let div = document.createElement('div'); // 2. Set its class to "alert" div.className = "alert"; -// Fill it with the content +// 3. Fill it with the content div.innerHTML = "Hi there! You've read an important message."; ``` diff --git a/2-ui/1-document/10-size-and-scroll-window/article.md b/2-ui/1-document/10-size-and-scroll-window/article.md index 5becf0a52..ff1b576a7 100644 --- a/2-ui/1-document/10-size-and-scroll-window/article.md +++ b/2-ui/1-document/10-size-and-scroll-window/article.md @@ -2,11 +2,19 @@ كيف نجد عرض وارتفاع نافذة المتصفح؟ كيف نحصل على العرض والارتفاع الكاملين للوثيقة ، بما في ذلك الجزء المسحوب؟ كيف ننتقل الصفحة باستخدام جافا سكريبت؟ +<<<<<<< HEAD بالنسبة لمعظم هذه الطلبات ، يمكننا استخدام عنصر المستند الجذر `document.documentElement` ، الذي يتوافق مع العلامة` `. ولكن هناك طرق وخصائص إضافية مهمة بما يكفي للنظر فيها. +======= +For this type of information, we can use the root document element `document.documentElement`, that corresponds to the `` tag. But there are additional methods and peculiarities to consider. +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a ## عرض / ارتفاع النافذة +<<<<<<< HEAD للحصول على عرض النافذة وارتفاعها ، يمكننا استخدام `clientWidth / clientHeight` من` document.documentElement`: +======= +To get window width and height, we can use the `clientWidth/clientHeight` of `document.documentElement`: +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a ![](document-client-width-height.svg) @@ -16,12 +24,21 @@ ``` +<<<<<<< HEAD ````warn header="ليس `window.innerWidth / Height`" كما تدعم المستعرضات الخصائص `window.innerWidth / innerHeight`. يبدون مثل ما نريد. فلماذا لا تستخدمها بدلاً من ذلك؟ إذا كان هناك شريط تمرير ، ويحتل بعض المساحة ، يوفر `clientWidth / clientHeight` العرض / الارتفاع بدونه (اطرحه). بمعنى آخر ، تقوم بإرجاع عرض / ارتفاع الجزء المرئي من المستند المتاح للمحتوى. ... و `window.innerWidth / innerHeight` تتضمن شريط التمرير. +======= +````warn header="Not `window.innerWidth/innerHeight`" +Browsers also support properties like `window.innerWidth/innerHeight`. They look like what we want, so why not to use them instead? + +If there exists a scrollbar, and it occupies some space, `clientWidth/clientHeight` provide the width/height without it (subtract it). In other words, they return the width/height of the visible part of the document, available for the content. + +`window.innerWidth/innerHeight` includes the scrollbar. +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a إذا كان هناك شريط تمرير ، ويشغل بعض المساحة ، فإن هذين الخطين يعرضان قيمًا مختلفة: ```js run @@ -29,7 +46,11 @@ alert( window.innerWidth ); // full window width alert( document.documentElement.clientWidth ); // window width minus the scrollbar ``` +<<<<<<< HEAD في معظم الحالات ، نحتاج إلى عرض النافذة * المتوفرة *: لرسم شيء ما أو وضعه. هذا هو: داخل أشرطة التمرير إذا كان هناك أي. لذا يجب علينا استخدام `documentElement.clientHeight / Width`. +======= +In most cases, we need the *available* window width in order to draw or position something within scrollbars (if there are any), so we should use `documentElement.clientHeight/clientWidth`. +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a ```` ````warn header=" "DOCTYPE` مهم" @@ -40,9 +61,15 @@ alert( document.documentElement.clientWidth ); // window width minus the scrollb ## عرض / ارتفاع الوثيقة +<<<<<<< HEAD نظريًا ، نظرًا لأن عنصر المستند الجذر هو `document.documentElement` ، ويشتمل على كل المحتوى ، يمكننا قياس حجم المستند بالكامل على أنه` document.documentElement.scrollWidth / ScrollHeight`. ولكن في هذا العنصر ، بالنسبة للصفحة بأكملها ، لا تعمل هذه الخصائص على النحو المنشود. في Chrome / Safari / Opera إذا لم يكن هناك تمرير ، فقد يكون `documentElement.scrollHeight` أقل من` documentElement.clientHeight`! يبدو هراء ، غريب ، أليس كذلك؟ +======= +Theoretically, as the root document element is `document.documentElement`, and it encloses all the content, we could measure the document's full size as `document.documentElement.scrollWidth/scrollHeight`. + +But on that element, for the whole page, these properties do not work as intended. In Chrome/Safari/Opera, if there's no scroll, then `documentElement.scrollHeight` may be even less than `documentElement.clientHeight`! Weird, right? +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a للحصول على ارتفاع المستند بشكل موثوق ، يجب أن نأخذ الحد الأقصى من هذه الخصائص: @@ -60,11 +87,19 @@ alert('Full document height, with scrolled out part: ' + scrollHeight); ## احصل على التمرير الحالي [# page-roll] +<<<<<<< HEAD عناصر DOM لها حالة التمرير الحالية في `elem.scrollLeft / rollTop`. بالنسبة إلى تمرير المستند ، يعمل المستند document.documentElement.scrollLeft / Top` في معظم المتصفحات ، باستثناء المتصفحات القديمة التي تستند إلى WebKit ، مثل Safari (الخطأ [5991] (https://bugs.webkit.org/show_bug.cgi؟id=5991) ) ، حيث يجب أن نستخدم `document.body` بدلاً من` document.documentElement`. لحسن الحظ ، ليس علينا أن نتذكر هذه الخصائص على الإطلاق ، لأن التمرير متاح في الخصائص الخاصة `window.pageXOffset/pageYOffset`: +======= +DOM elements have their current scroll state in their `scrollLeft/scrollTop` properties. + +For document scroll, `document.documentElement.scrollLeft/scrollTop` works in most browsers, except older WebKit-based ones, like Safari (bug [5991](https://bugs.webkit.org/show_bug.cgi?id=5991)), where we should use `document.body` instead of `document.documentElement`. + +Luckily, we don't have to remember these peculiarities at all, because the scroll is available in the special properties, `window.pageXOffset/pageYOffset`: +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a ```js run alert('Current scroll from the top: ' + window.pageYOffset); @@ -75,17 +110,31 @@ alert('Current scroll from the left: ' + window.pageXOffset); ## التمرير: التمرير إلى التمرير التمرير التمرير العرضي [# window-تمرير] +<<<<<<< HEAD احذر لتمرير الصفحة من JavaScript ، يجب بناء DOM بالكامل. على سبيل المثال ، إذا حاولنا تمرير الصفحة من البرنامج النصي في `` ، فلن تعمل. `` +======= +```warn +To scroll the page with JavaScript, its DOM must be fully built. + +For instance, if we try to scroll the page with a script in ``, it won't work. +``` +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a يمكن تمرير العناصر العادية عن طريق تغيير `التمرير / التمرير لليسار`. +<<<<<<< HEAD يمكننا فعل الشيء نفسه للصفحة باستخدام `document.documentElement.scrollTop / Left` (باستثناء Safari ، حيث يجب استخدام` document.body.scrollTop / Left` بدلاً من ذلك). بدلاً من ذلك ، هناك حل أبسط وعالمي: طرق خاصة [window.scrollBy (x، y)] (mdn: api / Window / rollBy) و [window.scrollTo (pageX، pageY)] (mdn: api / Window / rollTo) . +======= +We can do the same for the page using `document.documentElement.scrollTop/scrollLeft` (except Safari, where `document.body.scrollTop/Left` should be used instead). + +Alternatively, there's a simpler, universal solution: special methods [window.scrollBy(x,y)](mdn:api/Window/scrollBy) and [window.scrollTo(pageX,pageY)](mdn:api/Window/scrollTo). +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a - طريقة `التمرير (x، y) 'تقوم بتمرير الصفحة * بالنسبة إلى موقعها الحالي *. على سبيل المثال ، يؤدي `التمرير (0،10)` إلى تمرير الصفحة `10 بكسل` لأسفل. @@ -105,28 +154,50 @@ alert('Current scroll from the left: ' + window.pageXOffset); ## scrollIntoView +<<<<<<< HEAD للاستكمال ، دعنا نغطي طريقة أخرى: [elem.scrollIntoView (top)] (mdn: api / Element / rollIntoView). +======= +For completeness, let's cover one more method: [elem.scrollIntoView(top)](mdn:api/Element/scrollIntoView). +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a يؤدي استدعاء `elem.scrollIntoView (أعلى)` إلى تمرير الصفحة لإظهار `elem`. لها حجة واحدة: +<<<<<<< HEAD - إذا كان `top = true` (هذا هو الافتراضي) ، فسيتم تمرير الصفحة لإظهار` elem` في أعلى النافذة. يتم محاذاة الحافة العلوية للعنصر مع أعلى النافذة. - إذا كان `top = false` ، فتمرر الصفحة لتظهر` elem` في الأسفل. يتم محاذاة الحافة السفلية للعنصر مع أسفل النافذة. ```online يمرر الزر أدناه الصفحة لإظهار نفسها في أعلى النافذة: +======= +- If `top=true` (that's the default), then the page will be scrolled to make `elem` appear on the top of the window. The upper edge of the element will be aligned with the window top. +- If `top=false`, then the page scrolls to make `elem` appear at the bottom. The bottom edge of the element will be aligned with the window bottom. + +```online +The button below scrolls the page to position itself at the window top: +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a +<<<<<<< HEAD وهذا الزر يقوم بتمرير الصفحة لإظهارها في الأسفل: +======= +And this button scrolls the page to position itself at the bottom: +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a ``` ## منع التمرير +<<<<<<< HEAD نحتاج أحيانًا إلى جعل المستند "غير قابل للتمرير". على سبيل المثال ، عندما نحتاج إلى تغطيتها برسالة كبيرة تتطلب اهتمامًا فوريًا ، ونريد من الزائر أن يتفاعل مع هذه الرسالة ، وليس مع المستند. لجعل المستند غير قابل للتمرير ، يكفي تعيين `document.body.style.overflow =" hidden "`. سيتم تجميد الصفحة في التمرير الحالي. +======= +Sometimes we need to make the document "unscrollable". For instance, when we need to cover the page with a large message requiring immediate attention, and we want the visitor to interact with that message, not with the document. + +To make the document unscrollable, it's enough to set `document.body.style.overflow = "hidden"`. The page will "freeze" at its current scroll position. +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a ```online جربها: @@ -135,6 +206,7 @@ alert('Current scroll from the left: ' + window.pageXOffset); +<<<<<<< HEAD يجمد الزر الأول التمرير ، ويستأنفه الزر الثاني. `` @@ -143,13 +215,28 @@ alert('Current scroll from the left: ' + window.pageXOffset); عيب الطريقة هو اختفاء شريط التمرير. إذا كانت تحتل بعض المساحة ، فإن هذه المساحة الآن خالية ، ويزداد المحتوى لملئها. يبدو هذا غريبًا بعض الشيء ، ولكن يمكن التعامل معه إذا قارنا `ClientWidth` قبل التجميد وبعده ، وإذا زاد (اختفى شريط التمرير) ، فأضف` padding` إلى `document.body` بدلاً من شريط التمرير ، إلى حافظ على عرض المحتوى كما هو. +======= +The first button freezes the scroll, while the second one releases it. +``` + +We can use the same technique to freeze the scroll for other elements, not just for `document.body`. + +The drawback of the method is that the scrollbar disappears. If it occupied some space, then that space is now free and the content "jumps" to fill it. + +That looks a bit odd, but can be worked around if we compare `clientWidth` before and after the freeze. If it increased (the scrollbar disappeared), then add `padding` to `document.body` in place of the scrollbar to keep the content width the same. +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a ## الملخص الهندسة: +<<<<<<< HEAD - عرض / ارتفاع الجزء المرئي من المستند (عرض / ارتفاع منطقة المحتوى): `document.documentElement.clientWidth / Height` - عرض / ارتفاع الوثيقة بأكملها ، مع الجزء الممرر: +======= +- Width/height of the visible part of the document (content area width/height): `document.documentElement.clientWidth/clientHeight` +- Width/height of the whole document, with the scrolled out part: +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a ```js let scrollHeight = Math.max( diff --git a/2-ui/1-document/11-coordinates/article.md b/2-ui/1-document/11-coordinates/article.md index d7e57a918..d02183f32 100644 --- a/2-ui/1-document/11-coordinates/article.md +++ b/2-ui/1-document/11-coordinates/article.md @@ -88,8 +88,13 @@ right:${r.right} من الناحية العملية ، يُرجع `elem.getBoundingClientRect ()` دائمًا العرض / الارتفاع الموجب ، وهنا نذكر `العرض / الارتفاع` السلبي فقط لكي تفهم لماذا هذه الخصائص التي تبدو مكررة ليست في الواقع مكررة. ``` +<<<<<<< HEAD ```عنوان تحذيري"Internet Explorer و Edge: لا يوجد دعم لـ`x/y`" لا يدعم Internet Explorer و Edge خصائص `x / y` لأسباب تاريخية. +======= +```warn header="Internet Explorer: no support for `x/y`" +Internet Explorer doesn't support `x/y` properties for historical reasons. +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a لذلك يمكننا إما إنشاء ملف متعدد (أضف حروفًا في `DomRect.prototype`) أو فقط استخدام` أعلى / يسار` ، لأنها دائمًا ما تكون مثل `x / y` لـ` عرض / ارتفاع` إيجابي ، خاصة في نتيجة `elem.getBoundingClientRect ()`. ``` diff --git a/2-ui/2-events/01-introduction-browser-events/article.md b/2-ui/2-events/01-introduction-browser-events/article.md index cf16c9836..19394e49e 100644 --- a/2-ui/2-events/01-introduction-browser-events/article.md +++ b/2-ui/2-events/01-introduction-browser-events/article.md @@ -236,7 +236,7 @@ element.removeEventListener(event, handler, [options]); ````warn header="Removal requires the same function" To remove a handler we should pass exactly the same function as was assigned. -That doesn't work: +This doesn't work: ```js no-beautify elem.addEventListener( "click" , () => alert('Thanks!')); diff --git a/2-ui/2-events/02-bubbling-and-capturing/article.md b/2-ui/2-events/02-bubbling-and-capturing/article.md index d0faaf1ef..312dce5f9 100644 --- a/2-ui/2-events/02-bubbling-and-capturing/article.md +++ b/2-ui/2-events/02-bubbling-and-capturing/article.md @@ -204,9 +204,15 @@ elem.addEventListener("click", e => alert(2)); عندما يحدث حدث ما -- يكون العنصر الأكثر تداخل حيث يحدث يسمي "العنصر المستهدف" (`event.target`). +<<<<<<< HEAD - ثم ينتقل الحدث لأسفل من جذر المستند إلى `event.target`, مناديا علي المعالجات التي تم تعيينها مع `addEventListener(..., true)` بطريقة ما (`true` اختصار لـ `{capture: true}`). - ثم يتم استدعاء المعالجات على العنصر الهدف نفسه. - ثم يتم قذف الحدث لأعلي من`event.target` الي الجذر, مناديا علي المعالجات التي تم تعيينه باستخدام `on` و`addEventListener` مع او بدون القيمة الثالثة الممرة `false/{capture:false}`. +======= +- Then the event moves down from the document root to `event.target`, calling handlers assigned with `addEventListener(..., true)` on the way (`true` is a shorthand for `{capture: true}`). +- Then handlers are called on the target element itself. +- Then the event bubbles up from `event.target` to the root, calling handlers assigned using `on`, HTML attributes and `addEventListener` without the 3rd argument or with the 3rd argument `false/{capture:false}`. +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a يمكن لكل معالج الوصول إلى خصائص كائن "الحدث": @@ -220,6 +226,10 @@ elem.addEventListener("click", e => alert(2)); في العالم الحقيقي، حين يقع حادث ما, فالسلطات المحلية ترد أولاً. فهم يعرفون المنطقة التي حدث فيا جيدا. ثم سلطات أعلى مستوى إذا لزم الأمر. +<<<<<<< HEAD نفس الشيء بالنسبة لمعالجات الأحداث. الكود الذي يقوم بتعيين المعالج على عنصر معين يعرف الحد الأقصى من التفاصيل حول العنصر وما يفعله. قد يكون معالج على `` معين مناسبا بالضبط ل ``,فهو يعرف كل شيء عنه, لذا فلابد وأن تحظى بالفرصة أولاً. ثم يعرف الوالد المباشر أيضاً السياق, ولكن أقل قليلاً, وهكذا حتى العنصر العلوي الذي يعالج المفاهيم العامة ويدير العنصر الأخير. +======= +The same for event handlers. The code that set the handler on a particular element knows maximum details about the element and what it does. A handler on a particular `` may be suited for that exactly ``, it knows everything about it, so it should get the chance first. Then its immediate parent also knows about the context, but a little bit less, and so on till the very top element that handles general concepts and runs the last one. +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a وضع التدفق والالتقاط الأساس لـ "تفويض الحدث" -- نمط قوي للغاية للتعامل مع الأحداث ندرسه الفصل التالي. diff --git a/2-ui/2-events/03-event-delegation/article.md b/2-ui/2-events/03-event-delegation/article.md index df086f24b..41df9f079 100644 --- a/2-ui/2-events/03-event-delegation/article.md +++ b/2-ui/2-events/03-event-delegation/article.md @@ -5,7 +5,7 @@ Capturing and bubbling allow us to implement one of most powerful event handling The idea is that if we have a lot of elements handled in a similar way, then instead of assigning a handler to each of them -- we put a single handler on their common ancestor. -In the handler we get `event.target`, see where the event actually happened and handle it. +In the handler we get `event.target` to see where the event actually happened and handle it. Let's see an example -- the [Ba-Gua diagram](http://en.wikipedia.org/wiki/Ba_gua) reflecting the ancient Chinese philosophy. diff --git a/2-ui/2-events/05-dispatch-events/article.md b/2-ui/2-events/05-dispatch-events/article.md index 1a8e92ef1..b38719f85 100644 --- a/2-ui/2-events/05-dispatch-events/article.md +++ b/2-ui/2-events/05-dispatch-events/article.md @@ -8,7 +8,7 @@ We can generate not only completely new events, that we invent for our own purpo ## Event constructor -Build-in event classes form a hierarchy, similar to DOM element classes. The root is the built-in [Event](http://www.w3.org/TR/dom/#event) class. +Built-in event classes form a hierarchy, similar to DOM element classes. The root is the built-in [Event](http://www.w3.org/TR/dom/#event) class. We can create `Event` objects like this: @@ -162,7 +162,7 @@ Besides, the event class describes "what kind of event" it is, and if the event ## event.preventDefault() -Many browser events have a "default action", such as nagivating to a link, starting a selection, and so on. +Many browser events have a "default action", such as navigating to a link, starting a selection, and so on. For new, custom events, there are definitely no default browser actions, but a code that dispatches such event may have its own plans what to do after triggering the event. @@ -187,7 +187,6 @@ Any handler can listen for that event with `rabbit.addEventListener('hide',...)` ``` -Now `dispatchEvent` runs asynchronously after the current code execution is finished, including `mouse.onclick`, so event handlers are totally separate. +Now `dispatchEvent` runs asynchronously after the current code execution is finished, including `menu.onclick`, so event handlers are totally separate. The output order becomes: 1 -> 2 -> nested. @@ -283,9 +282,9 @@ Other constructors of native events like `MouseEvent`, `KeyboardEvent` and so on For custom events we should use `CustomEvent` constructor. It has an additional option named `detail`, we should assign the event-specific data to it. Then all handlers can access it as `event.detail`. -Despite the technical possibility to generate browser events like `click` or `keydown`, we should use with the great care. +Despite the technical possibility of generating browser events like `click` or `keydown`, we should use them with great care. -We shouldn't generate browser events as it's a hacky way to run handlers. That's a bad architecture most of the time. +We shouldn't generate browser events as it's a hacky way to run handlers. That's bad architecture most of the time. Native events might be generated: diff --git a/2-ui/3-event-details/1-mouse-events-basics/article.md b/2-ui/3-event-details/1-mouse-events-basics/article.md index 5cd846cd6..59fcd5572 100644 --- a/2-ui/3-event-details/1-mouse-events-basics/article.md +++ b/2-ui/3-event-details/1-mouse-events-basics/article.md @@ -25,6 +25,10 @@ : يعمل بعد النقر مرتين على نفس العنصر خلال فترة زمنية قصيرة. نادرا ما يستخدم في الوقت الحاضر. `contextmenu` +<<<<<<< HEAD +======= +: Triggers when the right mouse button is pressed. There are other ways to open a context menu, e.g. using a special keyboard key, it triggers in that case also, so it's not exactly the mouse event. +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a يعمل عندما يتم الضغط على زر الفأرة الأيمن. وهناك طرق أخرى لفتح قائمة السياق ، على سبيل المثال باستخدام مفتاح معين من لوحة المفاتيح ، ويمكن أيضًا استخدامه في هذه الحالة ، لذا فهو ليس بالضبط حدث للماوس . @@ -38,8 +42,12 @@ على سبيل المثال , عند النقر على الزر الايسر فإن أول حدث يتم تشغيله `mousedown`, عند الضغط على الزر, ثم `mouseup` وبالتالي أيضا `click` عند تحرير النقر. +<<<<<<< HEAD في الحالات التي يبدأ فيها إجراء واحد أحداثًا متعددة ، فإنه يتم إصلاح ترتيبها. بمعنى ، أنه يقوم باستدعاء الأحداث بالترتيب `mousedown` -> `mouseup` -> `click`. +======= +In cases when a single action initiates multiple events, their order is fixed. That is, the handlers are called in the order `mousedown` -> `mouseup` -> `click`. +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a ```online لمعاينة الأحداث بوضوح أنقر فوق الزر أدناه. جرب النقر مرتين أيضاً. @@ -56,23 +64,41 @@ تحتوي دائما الأحداث المتعلقة بالنقر على خاصية `button`, والتي تسمح لك بأستخدام زر الماوس. +<<<<<<< HEAD وعادة لا نستخدم هذه الخاصية لكل من هذين الحدثين `click` و `contextmenu` , وذلك لأن الأول يحدث فقط عند النقر بزر الماوس الأيسر ، والأخير - فقط عند النقر بزر الماوس الأيمن. من ناحية أخرى فإن, `mousedown` و `mouseup` قد تحتاج معالجتها إلى `event.button`, وذلك لأن هذه الأحداث من الممكن أن تعمل على أى زر لذا فإن `button` يتيح لك التمييز بين "زر الماوس الأيمن" و "زر الماوس الأيسر". +======= +We usually don't use it for `click` and `contextmenu` events, because the former happens only on left-click, and the latter -- only on right-click. + +From the other hand, `mousedown` and `mouseup` handlers may need `event.button`, because these events trigger on any button, so `button` allows to distinguish between "right-mousedown" and "left-mousedown". +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a القيم المحتملة لـ `event.button` هي: | حالة الزر | `event.button` | |--------------|----------------| +<<<<<<< HEAD | الزر الأيسر (أساسي) | 0 | | الزر الأوسط (مساعد) | 1 | | الزر الايمن (ثانوي) | 2 | | X1 زر (خلف) | 3 | | X2 زر (أمام) | 4 | +======= +| Left button (primary) | 0 | +| Middle button (auxiliary) | 1 | +| Right button (secondary) | 2 | +| X1 button (back) | 3 | +| X2 button (forward) | 4 | +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a تحتوي معظم أجهزة الماوس على الزرين الأيسر والأيمن فقط ، لذا فإن القيم المحتملة هي "0" أو "2". وكذلك الأجهزة التي تعمل باللمس أيضًا تولد أحداثًا مماثلة عندما ينقر عليها . +<<<<<<< HEAD هناك أيضًا خاصية `event.buttons` تحتوي على جميع الأزرار المضغوطة حاليًا كعدد صحيح ، بت واحد لكل زر. في الواقع ، نادرًا ما يتم استخدامها, يمكنك الرجوع الى مزيد من التفاصيل على [MDN](https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/buttons)اذا احتجت اليها في أي وقت. +======= +Also there's `event.buttons` property that has all currently pressed buttons as an integer, one bit per button. In practice this property is very rarely used, you can find details at [MDN](mdn:/api/MouseEvent/buttons) if you ever need it. +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a ```warn header="عفا عليها الزمن `event.which`" في الأكواد القديمة قد تجد استخدام خاصية `event.which` وهي تعتبر طريقة قديمة غير قياسية للحصول على زر ، مع القيم المحتملة : @@ -162,7 +188,11 @@ النقر المزدوج بزر الماوس له تأثير جانبي قد يكون غير ملائم في بعض الواجهات: فهو يحدد النص. +<<<<<<< HEAD على سبيل المثال, يؤدي النقر المزدوج على النص أدناه إلى تحديده بالإضافة إلى معالجنا: +======= +For instance, double-clicking on the text below selects it in addition to our handler: +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a ```html autorun height=50 أنقر مرتين علي diff --git a/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/article.md b/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/article.md index c7ac0d4db..d409c3f12 100644 --- a/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/article.md +++ b/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/article.md @@ -80,7 +80,7 @@ An important feature of `mouseout` -- it triggers, when the pointer moves from a
``` -If we're on `#parent` and then move the pointer deeper into `#child`, but we get `mouseout` on `#parent`! +If we're on `#parent` and then move the pointer deeper into `#child`, we get `mouseout` on `#parent`! ![](mouseover-to-child.svg) diff --git a/2-ui/3-event-details/4-mouse-drag-and-drop/article.md b/2-ui/3-event-details/4-mouse-drag-and-drop/article.md index a47bfade6..6cb1152c1 100644 --- a/2-ui/3-event-details/4-mouse-drag-and-drop/article.md +++ b/2-ui/3-event-details/4-mouse-drag-and-drop/article.md @@ -276,7 +276,7 @@ function onMouseMove(event) { } ``` -In the example below when the ball is dragged over the soccer gate, the gate is highlighted. +In the example below when the ball is dragged over the soccer goal, the goal is highlighted. [codetabs height=250 src="ball4"] @@ -300,4 +300,4 @@ We can lay a lot on this foundation. - We can use event delegation for `mousedown/up`. A large-area event handler that checks `event.target` can manage Drag'n'Drop for hundreds of elements. - And so on. -There are frameworks that build architecture over it: `DragZone`, `Droppable`, `Draggable` and other classes. Most of them do the similar stuff to what's described above, so it should be easy to understand them now. Or roll your own, as you can see that that's easy enough to do, sometimes easier than adapting a third-part solution. +There are frameworks that build architecture over it: `DragZone`, `Droppable`, `Draggable` and other classes. Most of them do the similar stuff to what's described above, so it should be easy to understand them now. Or roll your own, as you can see that that's easy enough to do, sometimes easier than adapting a third-party solution. diff --git a/2-ui/3-event-details/4-mouse-drag-and-drop/ball.view/index.html b/2-ui/3-event-details/4-mouse-drag-and-drop/ball.view/index.html index 36219e303..8751c70ad 100644 --- a/2-ui/3-event-details/4-mouse-drag-and-drop/ball.view/index.html +++ b/2-ui/3-event-details/4-mouse-drag-and-drop/ball.view/index.html @@ -13,7 +13,7 @@ ``` -Unlike most other controls, `` allows to select multiple options at once if it has `multiple` attribute. This attribute is rarely used though. + +For multiple selected values, use the first way of setting values: add/remove the `selected` property from ` ``` -The same element selected: +The same option, but selected: ```js let option = new Option("Text", "value", true, true); diff --git a/2-ui/4-forms-controls/2-focus-blur/article.md b/2-ui/4-forms-controls/2-focus-blur/article.md index d42013e5b..d4348d25b 100644 --- a/2-ui/4-forms-controls/2-focus-blur/article.md +++ b/2-ui/4-forms-controls/2-focus-blur/article.md @@ -1,6 +1,6 @@ # Focusing: focus/blur -An element receives a focus when the user either clicks on it or uses the `key:Tab` key on the keyboard. There's also an `autofocus` HTML attribute that puts the focus into an element by default when a page loads and other means of getting a focus. +An element receives the focus when the user either clicks on it or uses the `key:Tab` key on the keyboard. There's also an `autofocus` HTML attribute that puts the focus onto an element by default when a page loads and other means of getting the focus. Focusing on an element generally means: "prepare to accept the data here", so that's the moment when we can run the code to initialize the required functionality. @@ -18,7 +18,7 @@ Let's use them for validation of an input field. In the example below: -- The `blur` handler checks if the field the email is entered, and if not -- shows an error. +- The `blur` handler checks if the field has an email entered, and if not -- shows an error. - The `focus` handler hides the error message (on `blur` it will be checked again): ```html run autorun height=60 @@ -108,7 +108,7 @@ By default many elements do not support focusing. The list varies a bit between browsers, but one thing is always correct: `focus/blur` support is guaranteed for elements that a visitor can interact with: `
`; - // slottable is added/removed/replaced + // triggers when slot content changes *!* this.shadowRoot.firstElementChild.addEventListener('slotchange', e => { let slot = e.target; @@ -446,7 +446,7 @@ Composition does not really move nodes, from JavaScript point of view the DOM is JavaScript can access slots using methods: - `slot.assignedNodes/Elements()` -- returns nodes/elements inside the `slot`. -- `node.assignedSlot` -- the reverse meethod, returns slot by a node. +- `node.assignedSlot` -- the reverse property, returns slot by a node. If we'd like to know what we're showing, we can track slot contents using: - `slotchange` event -- triggers the first time a slot is filled, and on any add/remove/replace operation of the slotted element, but not its children. The slot is `event.target`. diff --git a/8-web-components/6-shadow-dom-style/article.md b/8-web-components/6-shadow-dom-style/article.md index 2be81fbb2..83a6962fa 100644 --- a/8-web-components/6-shadow-dom-style/article.md +++ b/8-web-components/6-shadow-dom-style/article.md @@ -259,7 +259,6 @@ For example, in shadow DOM we can use `--user-card-field-color` CSS variable to
Name:
Birthday:
- ``` Then, we can declare this property in the outer document for ``: diff --git a/9-regular-expressions/01-regexp-introduction/article.md b/9-regular-expressions/01-regexp-introduction/article.md index 8c3db47f0..0f22c02c6 100644 --- a/9-regular-expressions/01-regexp-introduction/article.md +++ b/9-regular-expressions/01-regexp-introduction/article.md @@ -29,7 +29,11 @@ regexp = /نمط/gmi; // أستخدام الاعلام g,m والعلم i (سي الأختلاف الرئيسي بين الطريقتين أن النمط بأستخدام ال `/.../` لا يسمح لك بكتابة تعبيرات بداخله (مثل التعبير `${...}`). في هذه الحاله تكون الجمله ثابتة. +<<<<<<< HEAD يتم استخدام الشرطة المائلة عندما نعرف التعبير العادي في وقت كتابة الكود -- وهذا هو الوضع الأكثر شيوعًا. بينما ال `new RegExp`, يتم استخدامه غالبًا عندما نحتاج إلى إنشاء regexp "على السريع" من سلسلة تم إنشاؤها ديناميكيًا. علي سبيل المثال: +======= +Slashes are used when we know the regular expression at the code writing time -- and that's the most common situation. While `new RegExp` is more often used when we need to create a regexp "on the fly" from a dynamically generated string. For instance: +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a ```js let tag = prompt("ما العلامة التي تريد العثور عليها؟", "h2"); @@ -56,7 +60,11 @@ let regexp = new RegExp(`<${tag}>`); // مثل /

/ أذا أُجيب "h2" ف : يمكننا وضع ال "dotall", يسمح النقطة `pattern:.` لمطابقة السطر الجديد `\n` (تم تغطيته في الفصل ). `pattern:u` +<<<<<<< HEAD : تمكين دعم Unicode الكامل. يتيح العلم المعالجة الصحيحة للأزواج البديلة. المزيد عن ذلك في الفصل . +======= +: Enables full Unicode support. The flag enables correct processing of surrogate pairs. More about that in the chapter . +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a `pattern:y` : وضع ال "Sticky": يبحث عن الموضع في النص (تم تغطيتها في الفصل ) diff --git a/9-regular-expressions/02-regexp-character-classes/article.md b/9-regular-expressions/02-regexp-character-classes/article.md index 1f578f444..ead2d94a6 100644 --- a/9-regular-expressions/02-regexp-character-classes/article.md +++ b/9-regular-expressions/02-regexp-character-classes/article.md @@ -7,7 +7,13 @@ *فئات الاحرف* هو رمز خاص يطابق أي رمز من مجموعة معينة. +<<<<<<< HEAD على سبيل المثال ، دعنا نعثر على الرقم الأول في رقم الهاتف: +======= +For the start, let's explore the "digit" class. It's written as `pattern:\d` and corresponds to "any single digit". + +For instance, let's find the first digit in the phone number: +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a ```js run let str = "+7(903)-123-45-67"; @@ -119,7 +125,11 @@ alert( "CS-4".match(regexp) ); // CS-4 alert( "CS 4".match(regexp) ); // CS 4 (المسافة تعتبر أيضاً حرف) ``` +<<<<<<< HEAD يرجى ملاحظة أن النقطة تعني "أي حرف" ، ولكن ليس "عدم وجود حرف". يجب أن يكون هناك حرف لمطابقته: +======= +Please note that a dot means "any character", but not the "absence of a character". There must be a character to match it: +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a ```js run alert( "CS4".match(/CS.4/) ); // الناتج يكون null لان لا يجود أي حرف موضع النقطة. @@ -143,10 +153,17 @@ alert( "A\nB".match(/A.B/) ); // null (لا متطابقة) alert( "A\nB".match(/A.B/s) ); // A\nB (match!) ``` +<<<<<<< HEAD ````warn header="لا يدعم في Firefox و IE و Edge" أفحص هذا الموقع للمزيد من المعلومات حول الدعم. وفي نفس وقت الكتابة لا تنتمي الي Firefox و IE و Edge. لحسن الحظ ، هناك بديل يعمل في كل مكان. نستطيع أستخدام تعبير منتظم مثل `pattern:[\s\S]` ليكون الناتج "أي حرف". +======= +````warn header="Not supported in IE" +The `pattern:s` flag is not supported in IE. + +Luckily, there's an alternative, that works everywhere. We can use a regexp like `pattern:[\s\S]` to match "any character" (this pattern will be covered in the article ). +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a ```js run alert( "A\nB".match(/A[\s\S]B/) ); // A\nB (الناتج!) @@ -178,7 +195,11 @@ alert( "1 - 5".match(/\d\s-\s\d/) ); // 1 - 5, أيضاً تعمل **المسافة تعتبر حرف. تساوي في الاهمية مع أي حرف أخر.** +<<<<<<< HEAD لا يمكننا إضافة مسافات أو إزالتها من التعبير المنتظم ونتوقع أن تعمل بالطريقة نفسها. +======= +We can't add or remove spaces from a regular expression and expect it to work the same. +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a بمعني أخر, في التعبير المنتظم كل الحروف لها أهمية, والمسافات أيضاً. ```` @@ -197,6 +218,10 @@ alert( "1 - 5".match(/\d\s-\s\d/) ); // 1 - 5, أيضاً تعمل ...ولكن هذا ليس كل شيء! +<<<<<<< HEAD يوفر ترميز Unicode ، الذي تستخدمه JavaScript للسلاسل ، العديد من الخصائص للأحرف ، مثل: اللغة التي ينتمي إليها الحرف (إذا كان حرفًا) فهو علامة ترقيم ، إلخ. +======= +Unicode encoding, used by JavaScript for strings, provides many properties for characters, like: which language the letter belongs to (if it's a letter), is it a punctuation sign, etc. +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a يمكننا البحث بهذه الخصائص أيضًا. هذا يتطلب العلم `pattern:u`, تم تغطيته في المقال التالي. diff --git a/9-regular-expressions/03-regexp-unicode/article.md b/9-regular-expressions/03-regexp-unicode/article.md index defbe15ab..3e981c80a 100644 --- a/9-regular-expressions/03-regexp-unicode/article.md +++ b/9-regular-expressions/03-regexp-unicode/article.md @@ -4,9 +4,9 @@ JavaScript uses [Unicode encoding](https://en.wikipedia.org/wiki/Unicode) for st That range is not big enough to encode all possible characters, that's why some rare characters are encoded with 4 bytes, for instance like `𝒳` (mathematical X) or `😄` (a smile), some hieroglyphs and so on. -Here are the unicode values of some characters: +Here are the Unicode values of some characters: -| Character | Unicode | Bytes count in unicode | +| Character | Unicode | Bytes count in Unicode | |------------|---------|--------| | a | `0x0061` | 2 | | ≈ | `0x2248` | 2 | @@ -33,27 +33,21 @@ Unlike strings, regular expressions have flag `pattern:u` that fixes such proble ## Unicode properties \p{...} -```warn header="Not supported in Firefox and Edge" -Despite being a part of the standard since 2018, unicode properties are not supported in Firefox ([bug](https://bugzilla.mozilla.org/show_bug.cgi?id=1361876)) and Edge ([bug](https://github.com/Microsoft/ChakraCore/issues/2969)). - -There's [XRegExp](http://xregexp.com) library that provides "extended" regular expressions with cross-browser support for unicode properties. -``` - Every character in Unicode has a lot of properties. They describe what "category" the character belongs to, contain miscellaneous information about it. For instance, if a character has `Letter` property, it means that the character belongs to an alphabet (of any language). And `Number` property means that it's a digit: maybe Arabic or Chinese, and so on. We can search for characters with a property, written as `pattern:\p{…}`. To use `pattern:\p{…}`, a regular expression must have flag `pattern:u`. -For instance, `\p{Letter}` denotes a letter in any of language. We can also use `\p{L}`, as `L` is an alias of `Letter`. There are shorter aliases for almost every property. +For instance, `\p{Letter}` denotes a letter in any language. We can also use `\p{L}`, as `L` is an alias of `Letter`. There are shorter aliases for almost every property. -In the example below three kinds of letters will be found: English, Georgean and Korean. +In the example below three kinds of letters will be found: English, Georgian and Korean. ```js run let str = "A ბ ㄱ"; alert( str.match(/\p{L}/gu) ); // A,ბ,ㄱ -alert( str.match(/\p{L}/g) ); // null (no matches, as there's no flag "u") +alert( str.match(/\p{L}/g) ); // null (no matches, \p doesn't work without the flag "u") ``` Here's the main character categories and their subcategories: @@ -127,7 +121,7 @@ alert("number: xAF".match(regexp)); // xAF Let's look for Chinese hieroglyphs. -There's a unicode property `Script` (a writing system), that may have a value: `Cyrillic`, `Greek`, `Arabic`, `Han` (Chinese) and so on, [here's the full list](https://en.wikipedia.org/wiki/Script_(Unicode)). +There's a Unicode property `Script` (a writing system), that may have a value: `Cyrillic`, `Greek`, `Arabic`, `Han` (Chinese) and so on, [here's the full list](https://en.wikipedia.org/wiki/Script_(Unicode)). To look for characters in a given writing system we should use `pattern:Script=`, e.g. for Cyrillic letters: `pattern:\p{sc=Cyrillic}`, for Chinese hieroglyphs: `pattern:\p{sc=Han}`, and so on: @@ -141,7 +135,7 @@ alert( str.match(regexp) ); // 你,好 ### Example: currency -Characters that denote a currency, such as `$`, `€`, `¥`, have unicode property `pattern:\p{Currency_Symbol}`, the short alias: `pattern:\p{Sc}`. +Characters that denote a currency, such as `$`, `€`, `¥`, have Unicode property `pattern:\p{Currency_Symbol}`, the short alias: `pattern:\p{Sc}`. Let's use it to look for prices in the format "currency, followed by a digit": diff --git a/9-regular-expressions/06-regexp-boundary/article.md b/9-regular-expressions/06-regexp-boundary/article.md index 7c9f442fe..06b5ac9f7 100644 --- a/9-regular-expressions/06-regexp-boundary/article.md +++ b/9-regular-expressions/06-regexp-boundary/article.md @@ -27,7 +27,7 @@ So, it matches the pattern `pattern:\bHello\b`, because: 2. Then matches the word `pattern:Hello`. 3. Then the test `pattern:\b` matches again, as we're between `subject:o` and a comma. -The pattern `pattern:\bHello\b` would also match. But not `pattern:\bHell\b` (because there's no word boundary after `l`) and not `Java!\b` (because the exclamation sign is not a wordly character `pattern:\w`, so there's no word boundary after it). +So the pattern `pattern:\bHello\b` would match, but not `pattern:\bHell\b` (because there's no word boundary after `l`) and not `Java!\b` (because the exclamation sign is not a wordly character `pattern:\w`, so there's no word boundary after it). ```js run alert( "Hello, Java!".match(/\bHello\b/) ); // Hello diff --git a/9-regular-expressions/07-regexp-escaping/article.md b/9-regular-expressions/07-regexp-escaping/article.md index ee1e9cac4..fef987c60 100644 --- a/9-regular-expressions/07-regexp-escaping/article.md +++ b/9-regular-expressions/07-regexp-escaping/article.md @@ -100,6 +100,12 @@ alert( "الفصل 5.1".match(regexp) ); // 5.1 ## الملخص +<<<<<<< HEAD - للبحث عن الرموز الخاصة `pattern:[ \ ^ $ . | ? * + ( )` حرفيا, نحن بحاجة الى إرفاقهم بشرطة مائلة للخلف `\` "(تخطيهم)" - نحن بحاجة أيضا الى تخطى `/` إذا كانت داخل `pattern:/.../` (ولكن ليست بداخل `new RegExp`) - عندما نمرر نصا الى `new RegExp`, نحن بحاجة الى مضاعفة الشرط المائلة للخلف `\\`, لأن النصوص المقتبسة تستهلك واحدة منهم. +======= +- To search for special characters `pattern:[ \ ^ $ . | ? * + ( )` literally, we need to prepend them with a backslash `\` ("escape them"). +- We also need to escape `/` if we're inside `pattern:/.../` (but not inside `new RegExp`). +- When passing a string to `new RegExp`, we need to double backslashes `\\`, cause string quotes consume one of them. +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a diff --git a/9-regular-expressions/08-regexp-character-sets-and-ranges/1-find-range-1/solution.md b/9-regular-expressions/08-regexp-character-sets-and-ranges/1-find-range-1/solution.md index 378471611..85c7748f7 100644 --- a/9-regular-expressions/08-regexp-character-sets-and-ranges/1-find-range-1/solution.md +++ b/9-regular-expressions/08-regexp-character-sets-and-ranges/1-find-range-1/solution.md @@ -5,7 +5,7 @@ Answers: **no, yes**. ```js run alert( "Java".match(/Java[^script]/) ); // null ``` -- Yes, because the part `pattern:[^script]` part matches the character `"S"`. It's not one of `pattern:script`. As the regexp is case-sensitive (no `pattern:i` flag), it treats `"S"` as a different character from `"s"`. +- Yes, because the `pattern:[^script]` part matches the character `"S"`. It's not one of `pattern:script`. As the regexp is case-sensitive (no `pattern:i` flag), it treats `"S"` as a different character from `"s"`. ```js run alert( "JavaScript".match(/Java[^script]/) ); // "JavaS" diff --git a/9-regular-expressions/08-regexp-character-sets-and-ranges/article.md b/9-regular-expressions/08-regexp-character-sets-and-ranges/article.md index cb6a27e9d..a1b8f896d 100644 --- a/9-regular-expressions/08-regexp-character-sets-and-ranges/article.md +++ b/9-regular-expressions/08-regexp-character-sets-and-ranges/article.md @@ -57,16 +57,16 @@ For instance: - **\d** -- is the same as `pattern:[0-9]`, - **\w** -- is the same as `pattern:[a-zA-Z0-9_]`, -- **\s** -- is the same as `pattern:[\t\n\v\f\r ]`, plus few other rare unicode space characters. +- **\s** -- is the same as `pattern:[\t\n\v\f\r ]`, plus few other rare Unicode space characters. ``` ### Example: multi-language \w As the character class `pattern:\w` is a shorthand for `pattern:[a-zA-Z0-9_]`, it can't find Chinese hieroglyphs, Cyrillic letters, etc. -We can write a more universal pattern, that looks for wordly characters in any language. That's easy with unicode properties: `pattern:[\p{Alpha}\p{M}\p{Nd}\p{Pc}\p{Join_C}]`. +We can write a more universal pattern, that looks for wordly characters in any language. That's easy with Unicode properties: `pattern:[\p{Alpha}\p{M}\p{Nd}\p{Pc}\p{Join_C}]`. -Let's decipher it. Similar to `pattern:\w`, we're making a set of our own that includes characters with following unicode properties: +Let's decipher it. Similar to `pattern:\w`, we're making a set of our own that includes characters with following Unicode properties: - `Alphabetic` (`Alpha`) - for letters, - `Mark` (`M`) - for accents, @@ -85,10 +85,10 @@ let str = `Hi 你好 12`; alert( str.match(regexp) ); // H,i,你,好,1,2 ``` -Of course, we can edit this pattern: add unicode properties or remove them. Unicode properties are covered in more details in the article . +Of course, we can edit this pattern: add Unicode properties or remove them. Unicode properties are covered in more details in the article . -```warn header="Unicode properties aren't supported in Edge and Firefox" -Unicode properties `pattern:p{…}` are not yet implemented in Edge and Firefox. If we really need them, we can use library [XRegExp](http://xregexp.com/). +```warn header="Unicode properties aren't supported in IE" +Unicode properties `pattern:p{…}` are not implemented in IE. If we really need them, we can use library [XRegExp](http://xregexp.com/). Or just use ranges of characters in a language that interests us, e.g. `pattern:[а-я]` for Cyrillic letters. ``` diff --git a/9-regular-expressions/10-regexp-greedy-and-lazy/1-lazy-greedy/task.md b/9-regular-expressions/10-regexp-greedy-and-lazy/1-lazy-greedy/task.md index b46f55917..596f61a4e 100644 --- a/9-regular-expressions/10-regexp-greedy-and-lazy/1-lazy-greedy/task.md +++ b/9-regular-expressions/10-regexp-greedy-and-lazy/1-lazy-greedy/task.md @@ -3,5 +3,5 @@ What's the match here? ```js -"123 456".match(/\d+? \d+?/g) ); // ? +alert( "123 456".match(/\d+? \d+?/g) ); // ? ``` diff --git a/9-regular-expressions/10-regexp-greedy-and-lazy/4-find-html-tags-greedy-lazy/task.md b/9-regular-expressions/10-regexp-greedy-and-lazy/4-find-html-tags-greedy-lazy/task.md index 8e96c921d..6759152ff 100644 --- a/9-regular-expressions/10-regexp-greedy-and-lazy/4-find-html-tags-greedy-lazy/task.md +++ b/9-regular-expressions/10-regexp-greedy-and-lazy/4-find-html-tags-greedy-lazy/task.md @@ -12,4 +12,4 @@ let str = '<> '; alert( str.match(regexp) ); // '', '', '' ``` -Here we assume that tag attributes may not contain `<` and `>` (inside squotes too), that simplifies things a bit. +Here we assume that tag attributes may not contain `<` and `>` (inside quotes too), that simplifies things a bit. diff --git a/9-regular-expressions/10-regexp-greedy-and-lazy/article.md b/9-regular-expressions/10-regexp-greedy-and-lazy/article.md index 79abc559d..2f656479d 100644 --- a/9-regular-expressions/10-regexp-greedy-and-lazy/article.md +++ b/9-regular-expressions/10-regexp-greedy-and-lazy/article.md @@ -88,7 +88,7 @@ These common words do not make it obvious why the regexp fails, so let's elabora That's probably not what we expected, but that's how it works. -**In the greedy mode (by default) a quantifier is repeated as many times as possible.** +**In the greedy mode (by default) a quantified character is repeated as many times as possible.** The regexp engine adds to the match as many characters as it can for `pattern:.+`, and then shortens that one by one, if the rest of the pattern doesn't match. @@ -109,7 +109,7 @@ let regexp = /".+?"/g; let str = 'a "witch" and her "broom" is one'; -alert( str.match(regexp) ); // witch, broom +alert( str.match(regexp) ); // "witch", "broom" ``` To clearly understand the change, let's trace the search step by step. @@ -179,7 +179,7 @@ let regexp = /"[^"]+"/g; let str = 'a "witch" and her "broom" is one'; -alert( str.match(regexp) ); // witch, broom +alert( str.match(regexp) ); // "witch", "broom" ``` The regexp `pattern:"[^"]+"` gives correct results, because it looks for a quote `pattern:'"'` followed by one or more non-quotes `pattern:[^"]`, and then the closing quote. @@ -293,9 +293,9 @@ alert( str2.match(regexp) ); // ,

لذلك ، سيتم العثور على العديد من النتائج حسب الحاجة ، وليس أكثر. +<<<<<<< HEAD على سبيل المثال من المحتمل أن يكون هناك 100 تطابق في النص ، ولكن في حلقة "for..of` وجدنا 5 منها ، ثم قررنا أنها كافية وقمنا بعمل" استراحة ". ثم لن يقضي المحرك وقتًا في العثور على 95 مباراة أخرى. `` +======= +E.g. there are potentially 100 matches in the text, but in a `for..of` loop we found 5 of them, then decided it's enough and made a `break`. Then the engine won't spend time finding other 95 matches. +``` +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a ## المجموعات المسماة diff --git a/9-regular-expressions/13-regexp-alternation/03-match-quoted-string/solution.md b/9-regular-expressions/13-regexp-alternation/03-match-quoted-string/solution.md index 75af36da5..bf3cc9951 100644 --- a/9-regular-expressions/13-regexp-alternation/03-match-quoted-string/solution.md +++ b/9-regular-expressions/13-regexp-alternation/03-match-quoted-string/solution.md @@ -2,10 +2,17 @@ خطوة بخطوة: +<<<<<<< HEAD - أولاً نبحث عن "نمط" الاقتباس الافتتاحي: " - ثم إذا كان لدينا نمط `` الشرطة المائلة للخلف '': `` (يجب علينا تقنيًا مضاعفته في النمط ، لأنه شخصية خاصة ، لذلك فهي خط مائل عكسي في الواقع) ، فإن أي حرف يكون جيدًا بعده (نقطة ). - وإلا فإننا نأخذ أي حرف باستثناء الاقتباس (وهذا يعني نهاية السلسلة) وشرطة مائلة للخلف (لمنع الخطوط المائلة العكسية الوحيدة ، يتم استخدام الشرطة المائلة للخلف فقط مع بعض الرموز الأخرى بعدها): `النمط: [^" \\] ` - ... وهلم جرا حتى آخر quote أو علامة افتباس . +======= +- First we look for an opening quote `pattern:"` +- Then if we have a backslash `pattern:\\` (we have to double it in the pattern because it is a special character), then any character is fine after it (a dot). +- Otherwise we take any character except a quote (that would mean the end of the string) and a backslash (to prevent lonely backslashes, the backslash is only used with some other symbol after it): `pattern:[^"\\]` +- ...And so on till the closing quote. +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a بشكل: diff --git a/9-regular-expressions/13-regexp-alternation/article.md b/9-regular-expressions/13-regexp-alternation/article.md index f0b36e1ee..55011418c 100644 --- a/9-regular-expressions/13-regexp-alternation/article.md +++ b/9-regular-expressions/13-regexp-alternation/article.md @@ -20,7 +20,11 @@ alert( str.match(regexp) ); // 'HTML', 'CSS', 'JavaScript' لقد رأينا بالفعل شيئًا مشابهًا - الأقواس المربعة. تسمح بالاختيار بين عدة أحرف ، على سبيل المثال `pattern: gr [ae] y` يطابق` match: gre` أو `match: grey`. +<<<<<<< HEAD تسمح الأقواس المربعة باستخدام الأحرف أو مجموعات الأحرف فقط. يسمح التناوب بأي تعبيرات. نمط regexp `: A | B | C` يعني أحد التعبيرات` A` أو `B` أو` C`. +======= +Square brackets allow only characters or character classes. Alternation allows any expressions. A regexp `pattern:A|B|C` means one of expressions `A`, `B` or `C`. +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a على سبيل المثال: @@ -33,7 +37,11 @@ alert( str.match(regexp) ); // 'HTML', 'CSS', 'JavaScript' ## مثال: regexp للوقت +<<<<<<< HEAD في المقالات السابقة ، كانت هناك مهمة لبناء regexp لوقت البحث في شكل `hh: mm` ، على سبيل المثال` 12: 00`. لكن `` النمط البسيط: \ d \ d: \ d \ d` غامض للغاية. يقبل `25: 99` كوقت (حيث تتطابق 99 ثانية مع النمط ، لكن ذلك الوقت غير صالح). +======= +In previous articles there was a task to build a regexp for searching time in the form `hh:mm`, for instance `12:00`. But a simple `pattern:\d\d:\d\d` is too vague. It accepts `25:99` as the time (as 99 minutes match the pattern, but that time is invalid). +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a كيف يمكننا صنع نمط أفضل؟ @@ -47,7 +55,11 @@ alert( str.match(regexp) ); // 'HTML', 'CSS', 'JavaScript' بعد ذلك ، يجب أن تكون الدقائق من `00` إلى` 59`. في لغة التعبير العادي التي يمكن كتابتها كـ `pattern: [0-5] \ d`: الرقم الأول` 0-5` ، ثم أي رقم. +<<<<<<< HEAD إذا صقنا الدقائق والثواني معًا ، نحصل على النمط: `pattern: [01] \ d | 2 [0-3]: [0-5] \ d`. +======= +If we glue hours and minutes together, we get the pattern: `pattern:[01]\d|2[0-3]:[0-5]\d`. +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a لقد انتهينا تقريبًا ، ولكن هناك مشكلة. يحدث "النمط البديل": | `الآن بين` النمط: [01] \ d` و "النمط: 2 [0-3]: [0-5] \ d`. diff --git a/9-regular-expressions/14-regexp-lookahead-lookbehind/1-find-non-negative-integers/solution.md b/9-regular-expressions/14-regexp-lookahead-lookbehind/1-find-non-negative-integers/solution.md index 0f2f17327..564608e75 100644 --- a/9-regular-expressions/14-regexp-lookahead-lookbehind/1-find-non-negative-integers/solution.md +++ b/9-regular-expressions/14-regexp-lookahead-lookbehind/1-find-non-negative-integers/solution.md @@ -1,7 +1,11 @@ regexp لرقم صحيح هو `pattern: \ d +`. +<<<<<<< HEAD يمكننا استبعاد السلبيات عن طريق إلحاقها بالمظهر السلبي: `pattern: (؟ >>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a على الرغم من أننا إذا جربناها الآن ، فقد نلاحظ نتيجة "إضافية" أخرى: diff --git a/9-regular-expressions/14-regexp-lookahead-lookbehind/2-insert-after-head/solution.md b/9-regular-expressions/14-regexp-lookahead-lookbehind/2-insert-after-head/solution.md index 31ceeca96..1512e5455 100644 --- a/9-regular-expressions/14-regexp-lookahead-lookbehind/2-insert-after-head/solution.md +++ b/9-regular-expressions/14-regexp-lookahead-lookbehind/2-insert-after-head/solution.md @@ -1,4 +1,8 @@ +<<<<<<< HEAD للإدراج بعد علامة `` ، يجب أن نجدها أولاً. يمكننا استخدام `نمط النقش العادي: ` لذلك. +======= +In order to insert after the `` tag, we must first find it. We can use the regular expression pattern `pattern:` for that. +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a في هذه المهمة ، لا نحتاج إلى تعديل علامة ``. نحتاج فقط لإضافة النص بعده. @@ -6,24 +10,29 @@ ```js run let str = '......'; -str = str.replace(//, '$&

Hello

'); +str = str.replace(//, '$&

Hello

'); alert(str); // ...

Hello

... ``` +<<<<<<< HEAD في السلسلة البديلة `$ &` تعني المطابقة نفسها ، أي جزء النص المصدر الذي يتوافق مع `pattern: `. يتم استبداله بمفرده بالإضافة إلى `

Hello

`. +======= +In the replacement string `$&` means the match itself, that is, the part of the source text that corresponds to `pattern:`. It gets replaced by itself plus `

Hello

`. +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a البديل هو استخدام lookbehind: ```js run let str = '......'; -str = str.replace(/(?<=)/, `

Hello

`); +str = str.replace(/(?<=)/, `

Hello

`); alert(str); // ...

Hello

... ``` كما ترون ، هناك فقط جزء وراء النظر في هذا التعبير العادي. +<<<<<<< HEAD يعمل مثل هذا: - في كل موضع في النص. - تحقق مما إذا كان مسبوقًا بـ `النمط: `. @@ -33,4 +42,16 @@ alert(str); // ...

Hello

... لذلك نستبدل "السطر الفارغ" ، مسبوقًا بـ "pattern: ` ، بـ `

Hello

`. هذا هو الإدراج بعد "". -ملاحظة. علامات Regexp ، مثل `pattern: s` و` pattern: i` يمكن أن تكون مفيدة أيضًا: `pattern: / / si`. تجعل علامة `pattern: s` علامة` `pattern: .` تتطابق مع حرف سطر جديد ، وعلامة 'pattern: i` تجعل` `pattern: ` تتطابق أيضًا مع `match: ` غير حساس لحالة الأحرف. \ No newline at end of file +ملاحظة. علامات Regexp ، مثل `pattern: s` و` pattern: i` يمكن أن تكون مفيدة أيضًا: `pattern: / / si`. تجعل علامة `pattern: s` علامة` `pattern: .` تتطابق مع حرف سطر جديد ، وعلامة 'pattern: i` تجعل` `pattern: ` تتطابق أيضًا مع `match: ` غير حساس لحالة الأحرف. +======= +It works like this: +- At every position in the text. +- Check if it's preceeded by `pattern:`. +- If it's so then we have the match. + +The tag `pattern:` won't be returned. The result of this regexp is literally an empty string, but it matches only at positions preceeded by `pattern:`. + +So we replaces the "empty line", preceeded by `pattern:`, with `

Hello

`. That's the insertion after ``. + +P.S. Regexp flags, such as `pattern:s` and `pattern:i` can also be useful: `pattern://si`. The `pattern:s` flag makes the dot `pattern:.` match a newline character, and `pattern:i` flag makes `pattern:` also match `match:` case-insensitively. +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a diff --git a/9-regular-expressions/14-regexp-lookahead-lookbehind/article.md b/9-regular-expressions/14-regexp-lookahead-lookbehind/article.md index 94690e216..1791c03fd 100644 --- a/9-regular-expressions/14-regexp-lookahead-lookbehind/article.md +++ b/9-regular-expressions/14-regexp-lookahead-lookbehind/article.md @@ -1,6 +1,10 @@ # Lookahead و lookbehind +<<<<<<< HEAD في بعض الأحيان نحتاج إلى العثور فقط على تلك المطابقات لنمط يتبعه أو يسبقه نمط آخر. +======= +Sometimes we need to find only those matches for a pattern that are followed or preceded by another pattern. +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a هناك صيغة خاصة لذلك ، تسمى "lookahead" و "lookbehind" ، يشار إليها معًا باسم "lookaround". @@ -58,7 +62,7 @@ alert( str.match(/\d+(?=\s)(?=.*30)/) ); // 1 ```js run let str = "2 turkeys cost 60€"; -alert( str.match(/\d+(?!€)/) ); // 2 (the price is skipped) +alert( str.match(/\d+\b(?!€)/g) ); // 2 (the price is not matched) ``` ## Lookbehind @@ -85,7 +89,7 @@ alert( str.match(/(?<=\$)\d+/) ); // 30 (skipped the sole number) ```js run let str = "2 turkeys cost $60"; -alert( str.match(/(?>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a في مثل هذه الحالة ، يقترح متصفح الويب إنهاء البرنامج النصي وإعادة تحميل الصفحة. ليس بالشيء الجيد بالتأكيد +<<<<<<< HEAD بالنسبة لجافا سكريبت من جانب الخادم ، قد تصبح ثغرة أمنية في حالة معالجة التعبيرات العادية لبيانات المستخدم. +======= +For server-side JavaScript such a regexp may hang the server process, that's even worse. So we definitely should take a look at it. +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a ## مثال +<<<<<<< HEAD لنفترض أن لدينا سلسلة ، ونود أن نتحقق مما إذا كانت تتكون من الكلمات `pattern: \ w +` مع مساحة `اختيارية` `pattern: \ s؟` بعد كل منها. سنستخدم نمط regexp `: ^ (\ w + \ s؟) * $` ، فهو يحدد 0 أو أكثر من هذه الكلمات. +======= +Let's say we have a string, and we'd like to check if it consists of words `pattern:\w+` with an optional space `pattern:\s?` after each. + +An obvious way to construct a regexp would be to take a word followed by an optional space `pattern:\w+\s?` and then repeat it with `*`. + +That leads us to the regexp `pattern:^(\w+\s?)*$`, it specifies zero or more such words, that start at the beginning `pattern:^` and finish at the end `pattern:$` of the line. +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a في العمل: @@ -25,36 +43,48 @@ alert( regexp.test("A good string") ); // true alert( regexp.test("Bad characters: $@#") ); // false ``` +<<<<<<< HEAD يبدو أنه يعمل. والنتيجة صحيحة. على الرغم من ذلك ، على سلاسل معينة يستغرق الكثير من الوقت. طالما أن محرك جافا سكريبت "توقف" مع استهلاك CPU بنسبة 100٪. إذا قمت بتشغيل المثال أدناه ، فربما لن ترى أي شيء ، لأن JavaScript سوف "يتعطل" فقط. سيتوقف متصفح الويب عن التفاعل مع الأحداث ، وستتوقف واجهة المستخدم عن العمل. بعد مرور بعض الوقت سيقترح إعادة تحميل الصفحة. لذا كن حذرًا مع هذا: +======= +The regexp seems to work. The result is correct. Although, on certain strings it takes a lot of time. So long that JavaScript engine "hangs" with 100% CPU consumption. + +If you run the example below, you probably won't see anything, as JavaScript will just "hang". A web-browser will stop reacting on events, the UI will stop working (most browsers allow only scrolling). After some time it will suggest to reload the page. So be careful with this: +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a ```js run let regexp = /^(\w+\s?)*$/; -let str = "An input string that takes a long time or even makes this regexp to hang!"; +let str = "An input string that takes a long time or even makes this regexp hang!"; // will take a very long time alert( regexp.test(str) ); ``` +<<<<<<< HEAD يمكن لبعض محركات التعبير العادي معالجة مثل هذا البحث ، ولكن معظمها لا يستطيع ذلك. +======= +To be fair, let's note that some regular expression engines can handle such a search effectively, for example V8 engine version starting from 8.8 can do that (so Google Chrome 88 doesn't hang here), while Firefox browser does hang. +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a ## مثال مبسط +<<<<<<< HEAD ما الأمر؟ لماذا "تعليق" التعبير العادي؟ +======= +What's the matter? Why does the regular expression hang? +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a لفهم ذلك ، دعنا نبسط المثال: إزالة المسافات `pattern: \ s؟`. ثم يصبح `النمط: ^ (\ w +) * $`. ولجعل الأمور أكثر وضوحًا ، دعنا نستبدل `pattern: \ w` بـ` pattern: \ d`. مازال التعبير العادي الناتج معلقًا ، على سبيل المثال: - - ```js run let regexp = /^(\d+)*$/; -let str = "012345678901234567890123456789!"; +let str = "012345678901234567890123456789z"; -// will take a very long time +// will take a very long time (careful!) alert( regexp.test(str) ); ``` @@ -62,17 +92,28 @@ alert( regexp.test(str) ); أولاً ، قد يلاحظ المرء أن نمط regexp `: (\ d +) *` غريب بعض الشيء. يبدو "نمط محدد الكمية: *` غريبًا. إذا أردنا رقمًا ، فيمكننا استخدام `pattern: \ d +`. +<<<<<<< HEAD في الواقع ، إن التعبير العادي مصطنع. لكن السبب في أنها بطيئة هو نفسه الذي رأيناه أعلاه. لذلك دعونا نفهمها ، ومن ثم سيصبح المثال السابق واضحًا. ماذا يحدث أثناء البحث عن `النمط: ^ (\ d +) * $` في السطر `الموضوع: 123456789!` (اختصارًا قليلاً للوضوح) ، لماذا يستغرق وقتًا طويلاً؟ 1. أولاً ، يحاول محرك regexp إيجاد رقم `النمط: \ d +`. نمط `plus +: 'جشع افتراضيًا ، لذلك يستهلك جميع الأرقام: +======= +Indeed, the regexp is artificial; we got it by simplifying the previous example. But the reason why it is slow is the same. So let's understand it, and then the previous example will become obvious. + +What happens during the search of `pattern:^(\d+)*$` in the line `subject:123456789z` (shortened a bit for clarity, please note a non-digit character `subject:z` at the end, it's important), why does it take so long? + +Here's what the regexp engine does: + +1. First, the regexp engine tries to find the content of the parentheses: the number `pattern:\d+`. The plus `pattern:+` is greedy by default, so it consumes all digits: +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a     ``     \ d + .......     (123456789) z     `` +<<<<<<< HEAD     ثم يحاول تطبيق مقياس كمية النجم ، ولكن لا يوجد المزيد من الأرقام ، لذا فهو لا يعطي أي شيء.     التالي في النمط هو "نهاية السلسلة": $ `، ولكن في النص لدينا` الموضوع:! `، لذلك لا يوجد تطابق: @@ -82,9 +123,23 @@ alert( regexp.test(str) );     \ d + ........ $     (123456789)!     `` +======= + After all digits are consumed, `pattern:\d+` is considered found (as `match:123456789`). + + Then the star quantifier `pattern:(\d+)*` applies. But there are no more digits in the text, so the star doesn't give anything. + + The next character in the pattern is the string end `pattern:$`. But in the text we have `subject:z` instead, so there's no match: + + ``` + X + \d+........$ + (123456789)z + ``` +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a 2. نظرًا لعدم وجود تطابق ، فإن نمط المحدد الكمي الجشع `: +` يقلل من عدد التكرار ، ويعيد حرفًا واحدًا إلى الوراء. +<<<<<<< HEAD     الآن `النمط: \ d +` يأخذ جميع الأرقام باستثناء آخر:     ``     \ d + ....... @@ -93,14 +148,32 @@ alert( regexp.test(str) ); 3. ثم يحاول المحرك متابعة البحث من الموضع الجديد (`9`).     يمكن تطبيق النجمة `نمط: (\ d +) *` - تعطي الرقم `تطابق: 9`: +======= + Now `pattern:\d+` takes all digits except the last one (`match:12345678`): + ``` + \d+....... + (12345678)9z + ``` +3. Then the engine tries to continue the search from the next position (right after `match:12345678`). + + The star `pattern:(\d+)*` can be applied -- it gives one more match of `pattern:\d+`, the number `match:9`: +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a     `` +<<<<<<< HEAD     \ d + ....... \ d +     (12345678) (9)!     ``     يحاول المحرك مطابقة `النمط: $` مرة أخرى ، لكنه يفشل ، لأنه يلبي `الموضوع:!`: +======= + \d+.......\d+ + (12345678)(9)z + ``` + + The engine tries to match `pattern:$` again, but fails, because it meets `subject:z` instead: +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a     ``                  X @@ -109,46 +182,83 @@ alert( regexp.test(str) );     `` +<<<<<<< HEAD 4. لا يوجد تطابق ، لذلك سيستمر المحرك في التراجع ، مما يقلل من عدد التكرار. يعمل التراجع بشكل عام على هذا النحو: يقلل محدد الكمية الجشع من عدد التكرار حتى يتمكن من ذلك. ثم ينقص محدد الكمية الجشع السابق ، وهكذا. +======= +4. There's no match, so the engine will continue backtracking, decreasing the number of repetitions. Backtracking generally works like this: the last greedy quantifier decreases the number of repetitions until it reaches the minimum. Then the previous greedy quantifier decreases, and so on. +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a     تتم محاولة جميع التركيبات الممكنة. هنا أمثلةهم.     يتكون الرقم الأول من `النمط: \ d +` من 7 أرقام ، ثم عدد من رقمين: +<<<<<<< HEAD     ``                  X     \ d + ...... \ d +     (1234567) (89)!     `` +======= + ``` + X + \d+......\d+ + (1234567)(89)z + ``` +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a     يتكون الرقم الأول من 7 أرقام ، ثم رقمان من رقم واحد لكل منهما: +<<<<<<< HEAD     ``                    X     \ d + ...... \ d + \ d +     (1234567) (8) (9)!     `` +======= + ``` + X + \d+......\d+\d+ + (1234567)(8)(9)z + ``` +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a     يتكون الرقم الأول من 6 أرقام ، ثم عدد 3 أرقام: +<<<<<<< HEAD     ``                  X     \ d + ....... \ d +     (123456) (789)!     `` +======= + ``` + X + \d+.......\d+ + (123456)(789)z + ``` +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a     يتكون الرقم الأول من 6 أرقام ، ثم رقمان: +<<<<<<< HEAD     ``                    X     \ d + ..... \ d + \ d +     (123456) (78) (9)!     `` +======= + ``` + X + \d+.....\d+ \d+ + (123456)(78)(9)z + ``` +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a     ...وما إلى ذلك وهلم جرا. هناك عدة طرق لتقسيم مجموعة من الأرقام `123456789` إلى أرقام. على وجه الدقة ، هناك 2 n -1 ، حيث `n` هو طول المجموعة. +<<<<<<< HEAD بالنسبة لـ `n = 20` ، هناك حوالي مليون تركيبة ، لـ` n = 30` - ألف مرة أكثر. تجربة كل واحد منهم هو بالضبط السبب في أن البحث يستغرق وقتًا طويلاً. ماذا أفعل؟ @@ -160,10 +270,25 @@ alert( regexp.test(str) ); بعض محركات التعبير العادي لديها اختبارات صعبة وأتمتة محدودة تسمح بتجنب المرور عبر جميع التركيبات أو تجعلها أسرع بكثير ، ولكن ليس جميع المحركات ، وليس في جميع الحالات. ## الرجوع إلى الكلمات والسلاسل +======= +There are many ways to split a sequence of digits `123456789` into numbers. To be precise, there are 2n-1, where `n` is the length of the sequence. + +- For `123456789` we have `n=9`, that gives 511 combinations. +- For a longer sequence with `n=20` there are about one million (1048575) combinations. +- For `n=30` - a thousand times more (1073741823 combinations). + +Trying each of them is exactly the reason why the search takes so long. +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a يحدث الشيء نفسه في مثالنا الأول ، عندما ننظر إلى الكلمات حسب النمط `pattern: ^ (\ w + \ s؟) * $` في السلسلة `subject: مدخل معلق!`. +<<<<<<< HEAD والسبب هو أن الكلمة يمكن تمثيلها كنمط `واحد: \ w +` أو العديد: +======= +The similar thing happens in our first example, when we look for words by pattern `pattern:^(\w+\s?)*$` in the string `subject:An input that hangs!`. + +The reason is that a word can be represented as one `pattern:\w+` or many: +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a ``` (input) @@ -175,7 +300,19 @@ alert( regexp.test(str) ); بالنسبة للإنسان ، من الواضح أنه قد لا يكون هناك تطابق ، لأن السلسلة تنتهي بعلامة تعجب `!` ، لكن التعبير العادي يتوقع حرفًا كلمة `نمط: \ w` أو نمط` مسافة: \ s` في النهاية. لكن المحرك لا يعرف ذلك. +<<<<<<< HEAD يحاول جميع التركيبات كيف أن نمط regexp `: (\ w + \ s؟) *` يمكن "استهلاك" السلسلة ، بما في ذلك المتغيرات ذات نمط `المسافات: (\ w + \ s) *` وبدونها `نمط: (\ w +) * `(لأن المساحات` pattern: \ s؟ `اختيارية). نظرًا لوجود العديد من هذه المجموعات ، فإن البحث يستغرق الكثير من الوقت. +======= +It tries all combinations of how the regexp `pattern:(\w+\s?)*` can "consume" the string, including variants with spaces `pattern:(\w+\s)*` and without them `pattern:(\w+)*` (because spaces `pattern:\s?` are optional). As there are many such combinations (we've seen it with digits), the search takes a lot of time. + +What to do? + +Should we turn on the lazy mode? + +Unfortunately, that won't help: if we replace `pattern:\w+` with `pattern:\w+?`, the regexp will still hang. The order of combinations will change, but not their total count. + +Some regular expression engines have tricky tests and finite automations that allow to avoid going through all combinations or make it much faster, but most engines don't, and it doesn't always help. +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a ## كيفية الإصلاح؟ @@ -183,39 +320,67 @@ alert( regexp.test(str) ); الأول هو تقليل عدد التركيبات الممكنة. +<<<<<<< HEAD دعنا نعيد كتابة التعبير العادي كـ `pattern: ^ (\ w + \ s) * \ w *` - سنبحث عن أي عدد من الكلمات متبوعًا بنمط `المسافة: (\ w + \ s) *` ، ثم ( اختياريًا) كلمة `pattern: \ w *`. +======= +Let's make the space non-optional by rewriting the regular expression as `pattern:^(\w+\s)*\w*$` - we'll look for any number of words followed by a space `pattern:(\w+\s)*`, and then (optionally) a final word `pattern:\w*`. +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a تعادل regexp هذه السابقة (تتطابق مع نفسها) وتعمل بشكل جيد: ```js run let regexp = /^(\w+\s)*\w*$/; -let str = "An input string that takes a long time or even makes this regex to hang!"; +let str = "An input string that takes a long time or even makes this regex hang!"; alert( regexp.test(str) ); // false ``` لماذا اختفت المشكلة؟ +<<<<<<< HEAD الآن النجمة `pattern: *` يذهب بعد `pattern: \ w + \ s` بدلاً من` pattern: \ w + \ s؟ `. أصبح من المستحيل تمثيل كلمة واحدة من السلسلة مع `نمط متعدد متتالي: \ w +`. يتم الآن توفير الوقت اللازم لتجربة هذه المجموعات. على سبيل المثال ، النقش السابق `pattern: (\ w + \ s؟) *` يمكن أن يتطابق مع الكلمة `subject: string` على هيئة` `pattern: \ w +`: +======= +That's because now the space is mandatory. -```js run -\w+\w+ -string +The previous regexp, if we omit the space, becomes `pattern:(\w+)*`, leading to many combinations of `\w+` within a single word + +So `subject:input` could be matched as two repetitions of `pattern:\w+`, like this: +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a + +``` +\w+ \w+ +(inp)(ut) ``` +<<<<<<< HEAD النمط السابق ، بسبب `` النمط: \ s` الاختياري للمتغيرات المسموح بها `النمط: \ w +` ، `النمط: \ w + \ s` ،` النمط: \ w + \ w + `وما إلى ذلك. مع النقش المُعاد كتابته `النمط: (\ w + \ s) *` ، هذا مستحيل: قد يكون هناك `نمط: \ w + \ s` أو` النمط: \ w + \ s \ w + \ s` ، ولكن ليس `النمط: \ w + \ w + `. لذلك تم تقليل عدد المجموعات بشكل كبير. +======= +The new pattern is different: `pattern:(\w+\s)*` specifies repetitions of words followed by a space! The `subject:input` string can't be matched as two repetitions of `pattern:\w+\s`, because the space is mandatory. + +The time needed to try a lot of (actually most of) combinations is now saved. +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a ## منع التراجع +<<<<<<< HEAD ليس من المناسب دائمًا إعادة كتابة regexp. وليس من الواضح دائمًا كيفية القيام بذلك. النهج البديل هو منع التراجع عن المقياس الكمي. يحاول محرك التعبيرات العادية العديد من المجموعات التي من الواضح أنها خاطئة للإنسان. +======= +It's not always convenient to rewrite a regexp though. In the example above it was easy, but it's not always obvious how to do it. + +Besides, a rewritten regexp is usually more complex, and that's not good. Regexps are complex enough without extra efforts. + +Luckily, there's an alternative approach. We can forbid backtracking for the quantifier. + +The root of the problem is that the regexp engine tries many combinations that are obviously wrong for a human. +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a على سبيل المثال في نمط regexp `: (\ d +) * $` من الواضح للإنسان ، أن `النمط: +` لا يجب التراجع عنه. إذا استبدلنا نمطًا `` واحدًا: \ d + `بنمطين` منفصلين: \ d + \ d + `، فلن يتغير شيء: @@ -227,16 +392,31 @@ string (1234)(56789)! ``` +<<<<<<< HEAD وفي المثال الأصلي `pattern: ^ (\ w + \ s؟) * $` قد نرغب في منع التراجع في `pattern: \ w +`. هذا هو: `النمط: \ w +` يجب أن يتطابق مع كلمة كاملة ، مع أقصى طول ممكن. ليست هناك حاجة لخفض عدد التكرارات في `النمط: \ w +` ، حاول تقسيمه إلى كلمتين `نمط: \ w + \ w +` وما إلى ذلك. تدعم محركات التعبير العادية الحديثة محددات الكمية الملكية لذلك. إنهم مثل الجشعين ، لكنهم لا يتراجعون (لذلك هم في الواقع أبسط من المحددات الكمية العادية). +======= +And in the original example `pattern:^(\w+\s?)*$` we may want to forbid backtracking in `pattern:\w+`. That is: `pattern:\w+` should match a whole word, with the maximal possible length. There's no need to lower the repetitions count in `pattern:\w+` or to split it into two words `pattern:\w+\w+` and so on. + +Modern regular expression engines support possessive quantifiers for that. Regular quantifiers become possessive if we add `pattern:+` after them. That is, we use `pattern:\d++` instead of `pattern:\d+` to stop `pattern:+` from backtracking. + +Possessive quantifiers are in fact simpler than "regular" ones. They just match as many as they can, without any backtracking. The search process without bracktracking is simpler. +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a هناك أيضًا ما يسمى "مجموعات الالتقاط الذري" - وهي طريقة لتعطيل التراجع داخل الأقواس. +<<<<<<< HEAD لسوء الحظ ، في JavaScript غير مدعومة. ولكن هناك طريقة أخرى. +======= +...But the bad news is that, unfortunately, in JavaScript they are not supported. + +We can emulate them though using a "lookahead transform". +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a ### انظروا إلى الإنقاذ! +<<<<<<< HEAD يمكننا منع التراجع باستخدام lookahead. النمط الذي يجب أن يتكرر من خلال "النمط: \ w" بقدر الإمكان بدون التراجع هو: "النمط: (؟ = (\ w +)) \ 1`. @@ -245,6 +425,19 @@ string - Lookahead `pattern:؟ =` يتطلع لأطول كلمة `pattern: \ w +` بدءًا من الموضع الحالي. - محتويات الأقواس مع `النمط:؟ = ...` لا يحفظها المحرك ، لذا قم بتغليف `النمط: \ w +` بين قوسين. ثم يقوم المحرك بحفظ محتوياتها - ... واسمح لنا بالإشارة إليها في النمط باسم "pattern: \ 1". +======= +So we've come to real advanced topics. We'd like a quantifier, such as `pattern:+` not to backtrack, because sometimes backtracking makes no sense. + +The pattern to take as many repetitions of `pattern:\w` as possible without backtracking is: `pattern:(?=(\w+))\1`. Of course, we could take another pattern instead of `pattern:\w`. + +That may seem odd, but it's actually a very simple transform. + +Let's decipher it: + +- Lookahead `pattern:?=` looks forward for the longest word `pattern:\w+` starting at the current position. +- The contents of parentheses with `pattern:?=...` isn't memorized by the engine, so wrap `pattern:\w+` into parentheses. Then the engine will memorize their contents +- ...And allow us to reference it in the pattern as `pattern:\1`. +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a هذا هو: نحن نتطلع إلى المستقبل - وإذا كانت هناك كلمة `pattern: \ w +` ، فقم بمطابقتها كـ `pattern: \ 1`. @@ -275,7 +468,7 @@ let regexp = /^((?=(\w+))\2\s?)*$/; alert( regexp.test("A good string") ); // true -let str = "An input string that takes a long time or even makes this regex to hang!"; +let str = "An input string that takes a long time or even makes this regex hang!"; alert( regexp.test(str) ); // false, works and fast! ``` @@ -286,7 +479,7 @@ alert( regexp.test(str) ); // false, works and fast! // parentheses are named ?, referenced as \k let regexp = /^((?=(?\w+))\k\s?)*$/; -let str = "An input string that takes a long time or even makes this regex to hang!"; +let str = "An input string that takes a long time or even makes this regex hang!"; alert( regexp.test(str) ); // false diff --git a/9-regular-expressions/16-regexp-sticky/article.md b/9-regular-expressions/16-regexp-sticky/article.md index cdbc9e82e..7b24a3263 100644 --- a/9-regular-expressions/16-regexp-sticky/article.md +++ b/9-regular-expressions/16-regexp-sticky/article.md @@ -3,11 +3,17 @@ تسمح العلامة `pattern: y` بالبحث في الموضع المحدد في السلسلة المصدر. +<<<<<<< HEAD لفهم حالة استخدام علامة "pattern: y" ، ومعرفة مدى روعتها ، دعنا نستكشف حالة استخدام عملية. إحدى المهام الشائعة لـ regexps هي "التحليل المعجمي": نحصل على نص ، على سبيل المثال في لغة البرمجة ، وتحليلها للعناصر الهيكلية. على سبيل المثال ، يحتوي HTML على علامات وسمات ، وشفرة JavaScript لها وظائف ، ومتغيرات ، وما إلى ذلك. +======= +To grasp the use case of `pattern:y` flag, and better understand the ways of regexps, let's explore a practical example. + +One of common tasks for regexps is "lexical analysis": we get a text, e.g. in a programming language, and need to find its structural elements. For instance, HTML has tags and attributes, JavaScript code has functions, variables, and so on. +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a تعد كتابة المحللات المعجمية مجالًا خاصًا ، مع أدواته وخوارزمياته الخاصة ، لذلك لا نتعمق في ذلك ، ولكن هناك مهمة مشتركة: قراءة شيء ما في الموضع المحدد. @@ -15,6 +21,7 @@ سنبحث عن اسم متغير باستخدام نمط regexp `: \ w +`. في الواقع ، تحتاج أسماء متغيرات جافا سكريبت إلى regexp أكثر تعقيدًا قليلاً لمطابقة دقيقة ، ولكن هنا لا يهم. +<<<<<<< HEAD استدعاء `str.match (/ \ w + /)` سيجد الكلمة الأولى فقط في السطر. أو جميع الكلمات التي تحمل علامة `pattern: g`. ولكننا نحتاج إلى كلمة واحدة فقط في الموضع `4`. للبحث من الموضع المحدد ، يمكننا استخدام الطريقة `regexp.exec (str)`. @@ -24,15 +31,33 @@ إذا كان هناك علامة `pattern: g` ، فسيتم البحث في السلسلة` str` ، بدءًا من الموضع المخزن في خاصية `regexp.lastIndex`. وإذا وجد تطابقًا ، فعيّن "regexp.lastIndex" إلى الفهرس بعد المباراة مباشرة. عند إنشاء regexp ، يكون "lastIndex" هو "0". +======= +- A call to `str.match(/\w+/)` will find only the first word in the line (`let`). That's not it. +- We can add the flag `pattern:g`. But then the call `str.match(/\w+/g)` will look for all words in the text, while we need one word at position `4`. Again, not what we need. + +**So, how to search for a regexp exactly at the given position?** + +Let's try using method `regexp.exec(str)`. + +For a `regexp` without flags `pattern:g` and `pattern:y`, this method looks only for the first match, it works exactly like `str.match(regexp)`. + +...But if there's flag `pattern:g`, then it performs the search in `str`, starting from position stored in the `regexp.lastIndex` property. And, if it finds a match, then sets `regexp.lastIndex` to the index immediately after the match. + +In other words, `regexp.lastIndex` serves as a starting point for the search, that each `regexp.exec(str)` call resets to the new value ("after the last match"). That's only if there's `pattern:g` flag, of course. +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a لذلك ، المكالمات المتتالية لعودة `regexp.exec (str)` تتطابق واحدة تلو الأخرى. +<<<<<<< HEAD مثال (بعلامة `pattern: g`): +======= +Here's an example of such calls: +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a ```js run -let str = 'let varName'; - +let str = 'let varName'; // Let's find all words in this string let regexp = /\w+/g; + alert(regexp.lastIndex); // 0 (initially lastIndex=0) let word1 = regexp.exec(str); @@ -48,9 +73,13 @@ alert(word3); // null (no more matches) alert(regexp.lastIndex); // 0 (resets at search end) ``` +<<<<<<< HEAD يتم إرجاع كل مباراة كمصفوفة بمجموعات وخصائص إضافية. يمكننا الحصول على جميع المباريات في الحلقة: +======= +We can get all matches in the loop: +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a ```js run let str = 'let varName'; @@ -65,11 +94,21 @@ while (result = regexp.exec(str)) { } ``` +<<<<<<< HEAD يعد استخدام `regexp.exec` بديلاً للطريقة` str.matchAll`. على عكس الطرق الأخرى ، يمكننا تعيين "lastIndex" الخاص بنا لبدء البحث من الموضع المحدد. على سبيل المثال ، دعنا نجد كلمة ، بدءًا من الموضع `4`: +======= +Such use of `regexp.exec` is an alternative to method `str.matchAll`, with a bit more control over the process. + +Let's go back to our task. + +We can manually set `lastIndex` to `4`, to start the search from the given position! + +Like this: +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a ```js run let str = 'let varName = "value"'; @@ -84,9 +123,21 @@ let word = regexp.exec(str); alert(word); // varName ``` +<<<<<<< HEAD أجرينا بحثًا عن `النمط: \ w +` ، بدءًا من الموضع `regexp.lastIndex = 4`. يرجى ملاحظة: يبدأ البحث في الموضع `lastIndex` ثم يذهب إلى أبعد من ذلك. إذا لم يكن هناك كلمة في الموضع `lastIndex` ، لكنها موجودة في مكان ما بعدها ، فسيتم العثور عليها: +======= +Hooray! Problem solved! + +We performed a search of `pattern:\w+`, starting from position `regexp.lastIndex = 4`. + +The result is correct. + +...But wait, not so fast. + +Please note: the `regexp.exec` call starts searching at position `lastIndex` and then goes further. If there's no word at position `lastIndex`, but it's somewhere after it, then it will be found: +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a ```js run let str = 'let varName = "value"'; @@ -94,17 +145,25 @@ let str = 'let varName = "value"'; let regexp = /\w+/g; *!* +// start the search from position 3 regexp.lastIndex = 3; */!* -let word = regexp.exec(str); +let word = regexp.exec(str); +// found the match at position 4 alert(word[0]); // varName alert(word.index); // 4 ``` +<<<<<<< HEAD ...So ، مع وضع علامة `pattern: g` خاصية` lastIndex` تحدد موضع البداية للبحث. ** وضع علامة على "النمط: y" يجعل "regexp.exec" ينظر بالضبط إلى الموضع "lastIndex" ، ليس قبله وليس بعده. ** +======= +For some tasks, including the lexical analysis, that's just wrong. We need to find a match exactly at the given position at the text, not somewhere after it. And that's what the flag `y` is for. + +**The flag `pattern:y` makes `regexp.exec` to search exactly at position `lastIndex`, not "starting from" it.** +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a هذا هو نفس البحث مع العلم `pattern: y`: @@ -122,6 +181,14 @@ alert( regexp.exec(str) ); // varName (word at position 4) كما نرى ، لا يتطابق regexp `pattern: / \ w + / y` في الموضع` 3` (على عكس العلم `pattern: g`) ، ولكنه يتطابق في الموضع` 4`. +<<<<<<< HEAD تخيل ، لدينا نص طويل ، ولا يوجد تطابق على الإطلاق. ثم البحث باستخدام العلامة `نقش: g` سيستمر حتى نهاية النص ، وسيستغرق هذا وقتًا أكثر بكثير من البحث باستخدام العلم` نقش: ص`. في مثل هذه المهام مثل التحليل المعجمي ، عادة ما تكون هناك العديد من عمليات البحث في موضع محدد. إن استخدام العلم `pattern: y` هو مفتاح الأداء الجيد. +======= +Not only that's what we need, there's an important performance gain when using flag `pattern:y`. + +Imagine, we have a long text, and there are no matches in it, at all. Then a search with flag `pattern:g` will go till the end of the text and find nothing, and this will take significantly more time than the search with flag `pattern:y`, that checks only the exact position. + +In tasks like lexical analysis, there are usually many searches at an exact position, to check what we have there. Using flag `pattern:y` is the key for correct implementations and a good performance. +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a diff --git a/9-regular-expressions/17-regexp-methods/article.md b/9-regular-expressions/17-regexp-methods/article.md index 5073bc74d..4430d8d38 100644 --- a/9-regular-expressions/17-regexp-methods/article.md +++ b/9-regular-expressions/17-regexp-methods/article.md @@ -20,7 +20,7 @@ Regular Expressions تعني سلسلة من الرموز والأحرف الت alert( result.length ); // 2 // Additional information: - alert( result.index ); // 0 (match position) + alert( result.index ); // 7 (match position) alert( result.input ); // I love JavaScript (source string) ``` @@ -95,13 +95,13 @@ alert( firstMatch.input ); //

Hello, world!

يمكننا استخدام `الانقسام` مع السلاسل ، مثل هذا: ```js run -alert('12-34-56'.split('-')) // array of [12, 34, 56] +alert('12-34-56'.split('-')) // array of ['12', '34', '56'] ``` لكن يمكننا تقسيمها بتعبير عادي ، بالطريقة نفسها: ```js run -alert('12, 34, 56'.split(/,\s*/)) // array of [12, 34, 56] +alert('12, 34, 56'.split(/,\s*/)) // array of ['12', '34', '56'] ``` ## str.search(regexp) @@ -142,7 +142,11 @@ alert('12-34-56'.replace("-", ":")) // 12:34-56 alert( '12-34-56'.replace( *!*/-/g*/!*, ":" ) ) // 12:34:56 ``` +<<<<<<< HEAD الُمدخَل الثاني هو سلسلة بديلة. يمكننا استخدام حرف خاص فيه: +======= +The second argument is a replacement string. We can use special characters in it: +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a | الرموز | الإجراء في سلسلة الاستبدال | |--------|--------| @@ -231,6 +235,23 @@ alert(result); // Smith, John يمنحنا استخدام دالة الطاقة البديلة القصوى ، لأنها تحصل على جميع المعلومات حول المباراة ، ولديها إمكانية الوصول إلى المتغيرات الخارجية ويمكنها القيام بكل شيء. +## str.replaceAll(str|regexp, str|func) + +This method is essentially the same as `str.replace`, with two major differences: + +1. If the first argument is a string, it replaces *all occurences* of the string, while `replace` replaces only the *first occurence*. +2. If the first argument is a regular expression without the `g` flag, there'll be an error. With `g` flag, it works the same as `replace`. + +The main use case for `replaceAll` is replacing all occurences of a string. + +Like this: + +```js run +// replace all dashes by a colon +alert('12-34-56'.replaceAll("-", ":")) // 12:34:56 +``` + + ## regexp.exec(str) تُظهر الطريقة `regexp.exec (str)` مطابقة لـ `regexp` في السلسلة` str`. على عكس الطرق السابقة ، يتم استدعاء regexp ، وليس على سلسلة. diff --git a/README.md b/README.md index 6564ef405..a631dd4a6 100755 --- a/README.md +++ b/README.md @@ -1,6 +1,10 @@ # The Modern JavaScript Tutorial in Arabic +<<<<<<< HEAD This repository hosts the translation of in Arabic. +======= +This repository hosts the English content of the Modern JavaScript Tutorial, published in [https://javascript.info](https://javascript.info). +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a **That's how you can contribute:** @@ -23,7 +27,13 @@ If maintainers do not respond, or if you'd like to become a maintainer, write us Your name and the contribution size will appear in the "About project" page when the translation gets published. +<<<<<<< HEAD P.S. The full list of languages can be found at . +======= +**You can edit the text in any editor.** The tutorial uses enhanced "markdown" format, easy to grasp. And if you want to see how it looks on-site, there's a server to run the tutorial locally at . + +The list of contributors is available at . +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a ## Structure @@ -102,7 +112,13 @@ document.querySelector('.hola').innerHTML = text; Please note, that sometimes code is followed by pictures, and if you translate text `Hello` -> `Hola` in the code, you need to translate text in picturess as well. +<<<<<<< HEAD In that case it's probably easier not to translate such text. See more about translating images later. +======= + - `index.md` stands for a chapter + - `article.md` stands for an article + - `task.md` stands for a task (solution must be provided in `solution.md` file as well) +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a ### External Links @@ -132,6 +148,7 @@ Some files, usually tasks, have YAML metadata at the top, delimited by `---`: ```md importance: 5 +<<<<<<< HEAD --- ... ``` @@ -168,3 +185,8 @@ image.svg: # image file You can run the tutorial server locally to see how the translation looks. The server and install instructions are at . +======= +--- +♥ +Ilya Kantor @iliakan +>>>>>>> 97ef86242f9f236b13152e1baf52a55c4db8728a diff --git a/figures.sketch b/figures.sketch index dfba26425..29ba3da17 100644 Binary files a/figures.sketch and b/figures.sketch differ