<?xml version="1.0"?>
<rss version="2.0"><channel><title>&#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x629;: &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A; JavaScript</title><link>https://academy.hsoub.com/programming/javascript/page/8/?d=2</link><description>&#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x629;: &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A; JavaScript</description><language>ar</language><item><title>&#x641;&#x647;&#x645; &#x627;&#x644;&#x623;&#x62D;&#x62F;&#x627;&#x62B; &#x627;&#x644;&#x645;&#x62A;&#x639;&#x644;&#x642;&#x629; &#x628;&#x62A;&#x62D;&#x631;&#x64A;&#x643; &#x627;&#x644;&#x641;&#x623;&#x631;&#x629; &#x648;&#x627;&#x644;&#x62A;&#x639;&#x627;&#x645;&#x644; &#x645;&#x639;&#x647;&#x627; &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A;</title><link>https://academy.hsoub.com/programming/javascript/%D9%81%D9%87%D9%85-%D8%A7%D9%84%D8%A3%D8%AD%D8%AF%D8%A7%D8%AB-%D8%A7%D9%84%D9%85%D8%AA%D8%B9%D9%84%D9%82%D8%A9-%D8%A8%D8%AA%D8%AD%D8%B1%D9%8A%D9%83-%D8%A7%D9%84%D9%81%D8%A3%D8%B1%D8%A9-%D9%88%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9%D9%87%D8%A7-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r1152/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_03/603e3222598ee_-------.png.f47b5ee5dcc23206f7aa3f0d89cea34d.png" /></p>

<p>
	لنتعمّق في المزيد من التفاصيل حول اﻷحداث التي تقع عندما تتحرّك الفأرة بين العناصر.
</p>

<h2>
	اﻷحداث mouseover/mouseout و relatedTarget
</h2>

<p>
	يقع الحدث <code>mouseover</code> عندما يأتي مؤشّر الفأرة إلى عنصر ما، ويقع <code>mouseout</code> عندما يغادره.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="58801" data-ss1614688784="1" href="https://academy.hsoub.com/uploads/monthly_2021_03/mouseover-mouseout.png.9094a317fefb36d301582261f51f92e7.png" rel=""><img alt="mouseover-mouseout.png" class="ipsImage ipsImage_thumbnailed" data-fileid="58801" data-unique="zy3tvfq61" src="https://academy.hsoub.com/uploads/monthly_2021_03/mouseover-mouseout.png.9094a317fefb36d301582261f51f92e7.png"></a>
</p>

<p>
	تتميّز هذه اﻷحداث بأنّ لديها الخاصيّة <code>relatedTarget</code>. تُكمِّل هذه الخاصيّةُ <code>target</code>. عندما تغادر الفأرة عنصرا ما نحو عنصر آخر، يصير إحدى هذه العناصر <code>target</code>، ويصير الآخر <code>relatedTarget</code>.
</p>

<p>
	بالنسبة للحدث <code>mouseover</code>:
</p>

<ul>
<li>
		<code>event.target</code> هو العنصر الذي أتت إليه الفأرة.
	</li>
	<li>
		<code>event.relatedTarget</code> هو العنصر الذي أتت منه الفأرة (<code>relatedTarget</code> -&gt; ‏<code>target</code>).
	</li>
</ul>
<p>
	والعكس بالنسبة للحدث <code>mouseout</code>:
</p>

<ul>
<li>
		<code>event.target</code> هو العنصر الذي غادرته الفأرة.
	</li>
	<li>
		<code>event.relatedTarget</code> هو العنصر الذي غادرت نحوه الفأرة، وصار تحت المؤشّر (<code>target</code> -&gt;‏ <code>relatedTarget</code>)
	</li>
</ul>
<p>
	في المثال التالي (يمكن مشاهدته من <a data-ss1614688784="1" href="https://plnkr.co/edit/3dGFqjP8JiDQPZg2?p=preview&amp;preview" rel="external nofollow">هنا</a>)، يشكّل كلُّ وجهٍ وتقاسيمُه عناصر منفصلة. عند تحريك الفأرة، يمكنك في المساحة النصيّة أسفله مشاهدة الأحداث التي تقع. يرافق كلَّ حدث المعلوماتُ المتعلّقة بكلٍّ من <code>target</code> و<code>relatedTarget</code>.
</p>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" data-ss1614688784="1" frameborder="no" height="332" loading="lazy" scrolling="no" src="https://codepen.io/Hsoub/embed/BaQxVWy?height=332&amp;theme-id=light&amp;default-tab=result" style="width: 100%;" title="JS-p2-mousemove-mouseover-mouseout-mouseenter-mouseleave-ex01">See the Pen JS-p2-mousemove-mouseover-mouseout-mouseenter-mouseleave-ex01 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<hr>
<p>
	<strong>تنبيه: يمكن أن يأخذ <code>relatedTarget</code> القيمة <code>null</code></strong>
</p>

<p>
	يمكن للخاصيّة <code>relatedTarget</code> أن تكون <code>null</code>. هذا أمر عاديّ ويعني فقط أنّ الفأرة لم تأتِ من عنصر آخر، ولكن من خارج النافذة. أو أنّها قد غادرت النافذة.
</p>

<hr>
<h2>
	تخطي العناصر
</h2>

<p>
	يقع الحدث <code>mousemove</code> عندما تتحرّك الفأرة. ولكنّ ذلك لا يعني أنّ كلَّ بكسل يؤدّي إلى حدث. يرصد المتصفّح الفأرة من وقت لآخر. وإذا لاحظ تغيّرات، فإنّه يعمل على وقوع اﻷحداث.
</p>

<p>
	هذا يعني لو حرّك المستخدم الفأرة بسرعة كبيرة فإنّ بعض عناصر DOM قد تُتخطّى:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="58800" data-ss1614688784="1" href="https://academy.hsoub.com/uploads/monthly_2021_03/mouseover-mouseout-over-elems.png.7e3f02615b8fda46973ba3c40a1c479f.png" rel=""><img alt="mouseover-mouseout-over-elems.png" class="ipsImage ipsImage_thumbnailed" data-fileid="58800" data-unique="8z4ez6sjg" src="https://academy.hsoub.com/uploads/monthly_2021_03/mouseover-mouseout-over-elems.png.7e3f02615b8fda46973ba3c40a1c479f.png"></a>
</p>

<p>
	إذا تحرّكت الفأرة بسرعة كبيرة من العنصر <code>‎#FROM</code> إلي العنصر <code>‎#TO</code> كما هو مبيّن أعلاه، فإنّ عناصر <code>&lt;div&gt;</code> التي بين هذين العنصرين (أو بعضها) قد تُتخطّى. قد يقع الحدث <code>mouseout</code> على <code>‎#FROM</code> ثم مباشرة على <code>‎#TO</code>.
</p>

<p>
	يساعد هذا على تحسين اﻷداء، لأنّه قد تكون هناك الكثير من العناصر البينيّة، ولا نريد حقًّا معالجة الدخول والخروج في كلٍّ منها.
</p>

<p>
	في المقابل، يجب أن ندرك دائما أن مؤشّر الفأرة لا "يزور" جميع العناصر في طريقه، بل قد "يقفز". فمثلا، من الممكن أن يقفز المؤشّر إلى وسط الصفحة مباشرة قادما من خارج الصفحة. في هذه الحالة، تكون قيمة <code>relatedTarget</code> هي <code>null</code>، لأنّه قد أتى من "لا مكان":
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="58799" data-ss1614688784="1" href="https://academy.hsoub.com/uploads/monthly_2021_03/mouseover-mouseout-from-outside.png.2a1a7c6c97a67c2b8641e1432eed4664.png" rel=""><img alt="mouseover-mouseout-from-outside.png" class="ipsImage ipsImage_thumbnailed" data-fileid="58799" data-unique="yfd2qmqaa" src="https://academy.hsoub.com/uploads/monthly_2021_03/mouseover-mouseout-from-outside.png.2a1a7c6c97a67c2b8641e1432eed4664.png"></a>
</p>

<p>
	يمكنك رؤية ذلك "حيًّا" في المثال التالي أو من منصّة الاختبار التي من <a data-ss1614688784="1" href="https://plnkr.co/edit/JPekeDa1wxumIXNT?p=preview" rel="external nofollow">هنا</a>:
</p>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" data-ss1614688784="1" frameborder="no" height="390" loading="lazy" scrolling="no" src="https://codepen.io/Hsoub/embed/mdOLKWY?height=390&amp;theme-id=light&amp;default-tab=result" style="width: 100%;" title="JS-p2-mousemove-mouseover-mouseout-mouseenter-mouseleave-ex02">See the Pen JS-p2-mousemove-mouseover-mouseout-mouseenter-mouseleave-ex02 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	يوجد هناك في HTML عنصران متداخلان: العنصر <code>&lt;div id="child"‎&gt;</code> موجود داخل العنصر <code>&lt;div id="parent"‎&gt;</code>. إذا حرّكتَ الفأرة بسرعة فوقهما، فربّما يقع الحدث على العنصر div الابن فقط، أو ربّما على اﻷب، أو ربّما لن تكون هناك أحداث مطلقا.
</p>

<p>
	قم أيضا بتحريك المؤشّر إلى داخل العنصر <code>div</code> الابن، ثم حرّكه بسرعة نحو اﻷسفل عبر العنصر اﻷب. إذا كانت الحركة سريعة كفاية، فسيُتجاهل العنصر اﻷب. ستعبر الفأرة العنصر اﻷب دون الانتباه له.
</p>

<hr>
<p>
	<strong>ملاحظة: إذا وقع <code>mouseover</code>، فلابدّ أن يكون هناك <code>mouseout</code></strong>
</p>

<p>
	في حالة تحرّك الفأرة بسرعة، فقد تُتجاهل العناصر البينيّة، لكن هناك شيء مؤكّد: إذا دخل المؤشّر "رسميًّا" إلى عنصر ما (تولًّد الحدثُ <code>mouseover</code>)، فعند مغادرته إيّاه سنحصل دائما على <code>mouseout</code>.
</p>

<hr>
<h2>
	Mouseout عند المغادرة نحو عنصر ابني
</h2>

<p>
	من الميزات المهمّة للحدث <code>mouseout</code> هي أنّه يقع عندما يتحّرك المؤشّر من عنصرٍ ما إلى عناصره السليلة، كأن يتحرّك من <code>‎#parent</code> إلى <code>‎#child</code> في شيفرة HTML هذه:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1221_7" style="">
<span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"parent"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"child"</span><span class="tag">&gt;</span><span class="pln">...</span><span class="tag">&lt;/div&gt;</span><span class="pln">
</span><span class="tag">&lt;/div&gt;</span></pre>

<p>
	فلو كنّا في <code>‎#parent</code> ثم حرّكنا المؤشّر إلى داخل <code>‎#child</code>، فسنتحصّل على <code>mouseout</code> في <code>‎#parent</code>!
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="58802" data-ss1614688784="1" href="https://academy.hsoub.com/uploads/monthly_2021_03/mouseover-to-child.png.242a1ab76555df7c0bb5a7c4f1de630a.png" rel=""><img alt="mouseover-to-child.png" class="ipsImage ipsImage_thumbnailed" data-fileid="58802" data-unique="h6nrux8pc" src="https://academy.hsoub.com/uploads/monthly_2021_03/mouseover-to-child.png.242a1ab76555df7c0bb5a7c4f1de630a.png"></a>
</p>

<p>
	قد يبدو هذا غريبا، لكن يمكن تفسيره بسهولة.
</p>

<p>
	<strong>حسب منطق المتصفّح، يمكن للمؤشّر أن يكون فوق عنصر <em>واحد</em> فقط في نفس الوقت، وهو العنصر الذي يأتي في اﻷسفل وفق ترتيب القيمة z-index.</strong>
</p>

<p>
	فإذا ذهب المؤشّر نحو عنصر آخر (ولو كان سليلًا)، فإنّه يغادر العنصر السابق.
</p>

<p>
	يُرجى التنبّه إلى جرئيّة مهمّة أخرى في معالجة اﻷحداث. ينتشر الحدث <code>mouseover</code> الذي يقع في عنصر سليل نحو اﻷعلى. فإذا كان للعنصر <code>‎#parent</code> معالج للحدث <code>mouseover</code> فإنّه سيشتغل:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="58798" data-ss1614688784="1" href="https://academy.hsoub.com/uploads/monthly_2021_03/mouseover-bubble-nested.png.b722153cde592c5e8ba24acb6eb7f151.png" rel=""><img alt="mouseover-bubble-nested.png" class="ipsImage ipsImage_thumbnailed" data-fileid="58798" data-unique="j358dvtym" src="https://academy.hsoub.com/uploads/monthly_2021_03/mouseover-bubble-nested.png.b722153cde592c5e8ba24acb6eb7f151.png"></a>
</p>

<p>
	يمكنك رؤية ذلك جيّدا في المثال الذي من <a data-ss1614688784="1" href="https://plnkr.co/edit/a7aOTFUzIkq1Cdrr?p=preview" rel="external nofollow">هنا</a>. العنصر <code>&lt;div id="child"‎&gt;</code> هو داخل العنصر <code>&lt;div id="parent"‎&gt;</code>. هناك معالجات لـ <code>mouseover/out</code> مسندة إلى العنصر <code>‎#parent</code> تعمل على إخراج تفاصيل الحدث.
</p>

<p>
	فإذا حرّكتَ الفأرةَ من <code>‎#parent</code> نحو <code>‎#child</code>، ستلاحظ وقوع حدثين في <code>‎#parent</code>:
</p>

<ol>
<li>
		<code>mouseout [target: parent]‎</code> (مغادرة المؤشّر للعنصر اﻷب)، ثم
	</li>
	<li>
		<code>mouseover [target: child]‎</code> (مجيء المؤشّر إلى العنصر الابن، انتشر هذا الحدث نحو اﻷعلى).
	</li>
</ol>
<p>
	<iframe allowfullscreen="true" allowtransparency="true" data-ss1614688784="1" frameborder="no" height="392" loading="lazy" scrolling="no" src="https://codepen.io/Hsoub/embed/LYbmryg?height=392&amp;theme-id=light&amp;default-tab=result" style="width: 100%;" title="JS-p2-mousemove-mouseover-mouseout-mouseenter-mouseleave-ex03">See the Pen JS-p2-mousemove-mouseover-mouseout-mouseenter-mouseleave-ex03 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	كما هو ظاهر، عندما يتحرّك المؤشّر من العنصر <code>‎#parent</code> نحو العنصر <code>‎#child</code>، يشتغل معالجان في العنصر اﻷب: <code>mouseout</code> و<code>mouseover</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1221_11" style="">
<span class="pln">parent</span><span class="pun">.</span><span class="pln">onmouseout </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">/* العنصر اﻷب :event.target */</span><span class="pln">
</span><span class="pun">};</span><span class="pln">
parent</span><span class="pun">.</span><span class="pln">onmouseover </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">/* العنصر الابن (انتشر نحو اﻷعلى)‏ :event.target */</span><span class="pln">
</span><span class="pun">};</span></pre>

<p>
	<strong>إذا لم نفحص <code>event.target</code> داخل المعالجات، فقد يبدو اﻷمر وكأنّ مؤشّر الفأرة قد غادر العنصر `‎#parent ثم عاد إليه مباشرة.</strong>
</p>

<p>
	لكن ليس اﻷمر كذلك! لا يزال المؤشر فوق العنصر اﻷب، وقد تحرّك فقط إلى داخل العنصر الابن.
</p>

<p>
	إذا كانت هناك أفعال تحصل بمغادرة العنصر اﻷبويّ مثل إجراء حركات في <code>parent.onmouseout</code>، فلا نودّ حصولها عادة بمجرّد انتقال المؤشّر في داخل <code>‎#parent</code>. لتجنّب ذلك، يمكننا تفحّص <code>relatedTarget</code> في المعالج، وإذا كان المؤشّر لا يزال داخل العنصر، فإنّنا نتجاهل الحدث. أو بدلًا عن ذلك، يمكننا استخدام اﻷحداث <code>mouseenter</code> و<code>mouseleave</code> التي سنتناولها الآن، إذ ليس لها مثل هذه المشاكل.
</p>

<h2>
	اﻷحداث mouseenter وmouseleave
</h2>

<p>
	الأحداث <code>mouseenter/mouseleave</code> مثل الأحداث <code>mouseover/mouseout</code>، فهي تقع عندما يدخل/يغادر مؤشّر الفأرة العنصر. لكن هناك فرقان مهمّان:
</p>

<ol>
<li>
		لا تُحتسب الانتقالات التي تحدث داخل العنصر، من وإلى عناصره السليلة.
	</li>
	<li>
		لا تنتشر الأحداث <code>mouseenter/mouseleave</code> نحو الأعلى.
	</li>
</ol>
<p>
	هذه الأحداث بسيطة للغاية. عندما يدخل المؤشّر العنصر، يقع <code>mouseenter</code>، ولا يهمّ مكانه داخل العنصر أو داخل عناصره السليلة بالضبط. ثمّ عندما يغادر المؤشّر العنصر، يقع <code>mouseleave</code>.
</p>

<p>
	يشبه المثال الذي يمكن مشاهدته من <a data-ss1614688784="1" href="https://plnkr.co/edit/ApJzT0t69pMyJPmq?p=preview&amp;preview" rel="external nofollow">هنا</a> المثال أعلاه، لكن العنصر العلويّ الآن لديه <code>mouseenter/mouseleave</code> بدل <code>mouseover/mouseout</code>.
</p>

<p>
	مثلما يمكن أن ترى، الأحداث التي تولّدت هي الأحداث الناتجة عن تحريك المؤشّر إلى داخل وخارج العنصر العلويّ فقط. لا شيء يحدث عندما يذهب المؤشر إلى العنصر الابن ويرجع. تُتجاهل الانتقالات بين العناصر السليلة.
</p>

<h2>
	تفويض الأحداث
</h2>

<p>
	الأحداث <code>mouseenter/leave</code> بسيطة للغاية وسهلة الاستخدام. لكنّها لا تنتشر نحو الأعلى. بالتالي لا يمكننا استخدام تفويض الأحداث معها.
</p>

<p>
	تصوّر أنّنا نريد معالجة دخول/مغادرة الفأرة لخانات جدول ما. وهناك المئات من الخانات.
</p>

<p>
	بكون الحلّ الطبيعيّ عادةً بإسناد المعالج إلى <code>&lt;table&gt;</code> ومعالجة الأحداث هناك. لكنّ <code>mouseenter/leave</code> لا تنتشر نحو الأعلى. فإذا وقعت الأحداث في <code>&lt;td&gt;</code>، فلا يمكن التقاطها إلّا بواسطة معالج مُسنَد إلى ذلك العنصر <code>&lt;td&gt;</code>.
</p>

<p>
	تشتغل المعالجات المسندة إلى <code>&lt;table&gt;</code> فقط عندما يدخل/يغادر المؤشّر الجدول ككلّ. يستحيل الحصول على أيّة معلومات حول الانتقالات داخله.
</p>

<p>
	لذا، فلنستخدم <code>mouseover/mouseout</code>. لنبدأ بمعالجات بسيطة تعمل على إبراز العنصر الذي تحت المؤشّر.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1221_13" style="">
<span class="com">// لنبرز العنصر الذي تحت المؤشّر</span><span class="pln">
table</span><span class="pun">.</span><span class="pln">onmouseover </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  let target </span><span class="pun">=</span><span class="pln"> event</span><span class="pun">.</span><span class="pln">target</span><span class="pun">;</span><span class="pln">
  target</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">background </span><span class="pun">=</span><span class="pln"> </span><span class="str">'pink'</span><span class="pun">;</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

table</span><span class="pun">.</span><span class="pln">onmouseout </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  let target </span><span class="pun">=</span><span class="pln"> event</span><span class="pun">.</span><span class="pln">target</span><span class="pun">;</span><span class="pln">
  target</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">background </span><span class="pun">=</span><span class="pln"> </span><span class="str">''</span><span class="pun">;</span><span class="pln">
</span><span class="pun">};</span></pre>

<p>
	يمكنك مشاهدتها تعمل من <a data-ss1614688784="1" href="%E2%80%8E%E2%80%8Ehttps://plnkr.co/edit/bYA8iBDQXZlqYdfW?p=preview&amp;preview" rel="">هنا</a>. كلّما تنقّلت الفأرة عبر العناصر في هذا الجدول، سيكون العنصر الحالي بارزا على الدوام:
</p>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" data-ss1614688784="1" frameborder="no" height="528" loading="lazy" scrolling="no" src="https://codepen.io/Hsoub/embed/NWbMzaN?height=528&amp;theme-id=light&amp;default-tab=result" style="width: 100%;" title="JS-p2-mousemove-mouseover-mouseout-mouseenter-mouseleave-ex04">See the Pen JS-p2-mousemove-mouseover-mouseout-mouseenter-mouseleave-ex04 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	في حالتنا هذه نودّ أن نعالج الانتقالات بين خانات الجدول <code>&lt;td&gt;</code>، أي عند دخول خانة أو مغادرتها. لا تهمّنا الانتقالات الأخرى كالتي تحصل داخل الخانة أو خارج كلّ الخانات. لنُنحّيها جانبا.
</p>

<p>
	هذا ما يمكننا فعله:
</p>

<ul>
<li>
		حفظ العنصر <code>&lt;td&gt;</code> المُبرَز حاليّا في متغيّر، ولنسمّيه <code>currentElem</code>.
	</li>
	<li>
		تجاهل الحدث <code>mouseover</code> عند وقوعه في داخل العنصر <code>&lt;td&gt;</code> الحالي.
	</li>
</ul>
<p>
	هذا مثال لشيفرة تأخذ جميع الحالات الممكنة في الحسبان:
</p>

<p>
	 
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1221_15" style="">
<span class="com">// التي تحت الفأرة الآن (إن وُجدت)‏ &lt;td&gt; </span><span class="pln">
let currentElem </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">;</span><span class="pln">

table</span><span class="pun">.</span><span class="pln">onmouseover </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// قبل دخول عنصر جديد، تغادر الفأرة دائما العنصر السابق</span><span class="pln">
  </span><span class="com">//  السابق &lt;td&gt; نفسه، فإنّنا لم نغادر currentElem إذا بقي العنصر</span><span class="pln">
  </span><span class="com">// بداخله، تجاهل الحدث mouseover هذا مجرّد </span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">currentElem</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">return</span><span class="pun">;</span><span class="pln">

  let target </span><span class="pun">=</span><span class="pln"> event</span><span class="pun">.</span><span class="pln">target</span><span class="pun">.</span><span class="pln">closest</span><span class="pun">(</span><span class="str">'td'</span><span class="pun">);</span><span class="pln">

  </span><span class="com">// تجاهل - &lt;td&gt; تحرّكنا إلى غير </span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(!</span><span class="pln">target</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">return</span><span class="pun">;</span><span class="pln">

  </span><span class="com">// لكن خارج جدولنا (يمكن ذلك في حالة الجداول المتداخلة)‏ &lt;td&gt; تحرّكنا داخل</span><span class="pln">
  </span><span class="com">// تجاهل</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(!</span><span class="pln">table</span><span class="pun">.</span><span class="pln">contains</span><span class="pun">(</span><span class="pln">target</span><span class="pun">))</span><span class="pln"> </span><span class="kwd">return</span><span class="pun">;</span><span class="pln">
  
  </span><span class="com">// جديد &lt;td&gt; مرحا! دخلنا</span><span class="pln">
  currentElem </span><span class="pun">=</span><span class="pln"> target</span><span class="pun">;</span><span class="pln">
  onEnter</span><span class="pun">(</span><span class="pln">currentElem</span><span class="pun">);</span><span class="pln">
</span><span class="pun">};</span><span class="pln">


table</span><span class="pun">.</span><span class="pln">onmouseout </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// الآن، تجاهل الحدث &lt;td&gt; إذا كنّا خارج أيّ</span><span class="pln">
  </span><span class="com">// &lt;td&gt; يُحتمل أنّ هذا تحرّك داخل الجدول، ولكن خارج</span><span class="pln">
  </span><span class="com">// آخر &lt;tr&gt; إلى &lt;tr&gt; مثلا من</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(!</span><span class="pln">currentElem</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">return</span><span class="pun">;</span><span class="pln">

  </span><span class="com">// نحن بصدد مغادرة العنصر – إلى أين؟ ربمّا إلى عنصر سليل؟</span><span class="pln">
  let relatedTarget </span><span class="pun">=</span><span class="pln"> event</span><span class="pun">.</span><span class="pln">relatedTarget</span><span class="pun">;</span><span class="pln">

  </span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="pln">relatedTarget</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// currentElem اصعد مع سلسلة الآباء وتحقّق إذا كنّا لا نزال داخل  </span><span class="pln">
    </span><span class="com">//  فهو إذًا انتقال داخليّ – تجاهله </span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">relatedTarget </span><span class="pun">==</span><span class="pln"> currentElem</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">return</span><span class="pun">;</span><span class="pln">

    relatedTarget </span><span class="pun">=</span><span class="pln"> relatedTarget</span><span class="pun">.</span><span class="pln">parentNode</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="com">// .حقًّا .&lt;td&gt; لقد غادرنا العنصر</span><span class="pln">
  onLeave</span><span class="pun">(</span><span class="pln">currentElem</span><span class="pun">);</span><span class="pln">
  currentElem </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">;</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

</span><span class="com">// أيّة دالّة لمعالجة دخول/مغادرة العنصر</span><span class="pln">
</span><span class="kwd">function</span><span class="pln"> onEnter</span><span class="pun">(</span><span class="pln">elem</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  elem</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">background </span><span class="pun">=</span><span class="pln"> </span><span class="str">'pink'</span><span class="pun">;</span><span class="pln">

  </span><span class="com">// أظهر ذلك في المساحة النصيّة</span><span class="pln">
  text</span><span class="pun">.</span><span class="pln">value </span><span class="pun">+=</span><span class="pln"> </span><span class="pun">`</span><span class="pln">over </span><span class="pun">-&gt;</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">currentElem</span><span class="pun">.</span><span class="pln">tagName</span><span class="pun">}.</span><span class="pln">$</span><span class="pun">{</span><span class="pln">currentElem</span><span class="pun">.</span><span class="pln">className</span><span class="pun">}</span><span class="pln">\n</span><span class="pun">`;</span><span class="pln">
  text</span><span class="pun">.</span><span class="pln">scrollTop </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1e6</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> onLeave</span><span class="pun">(</span><span class="pln">elem</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  elem</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">background </span><span class="pun">=</span><span class="pln"> </span><span class="str">''</span><span class="pun">;</span><span class="pln">

  </span><span class="com">// أظهر ذلك في المساحة النصيّة</span><span class="pln">
  text</span><span class="pun">.</span><span class="pln">value </span><span class="pun">+=</span><span class="pln"> </span><span class="pun">`</span><span class="pln">out </span><span class="pun">&lt;-</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">elem</span><span class="pun">.</span><span class="pln">tagName</span><span class="pun">}.</span><span class="pln">$</span><span class="pun">{</span><span class="pln">elem</span><span class="pun">.</span><span class="pln">className</span><span class="pun">}</span><span class="pln">\n</span><span class="pun">`;</span><span class="pln">
  text</span><span class="pun">.</span><span class="pln">scrollTop </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1e6</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	مرّة أخرى، أهمّ ما يميّز هذه الطريقة هو التالي:
</p>

<ol>
<li>
		تستخدم تفويض الأحداث لمعالجة دخول/مغادرة أيّ <code>&lt;td&gt;</code> داخل الجدول. فهي تعتمد على <code>mouseover/out</code> بدل <code>mouseenter/leave</code> التي لا تنتشر نحو الأعلى وبذلك لا تسمح بتفويض الأحداث.
	</li>
	<li>
		تُنحّى الأحداث الأخرى، مثل التنقّل بين العناصر السليلة لـ <code>&lt;td&gt;</code>، جانبًا لكيلا تشتغل المعالجات <code>onEnter/Leave</code> إلّا عندما يدخل أو يغادر المؤشّر <code>&lt;td&gt;</code> ككلّ.
	</li>
</ol>
<p>
	يمكنك مشاهدة المثال كاملا بجميع التفاصيل من <a data-ss1614688784="1" href="https://plnkr.co/edit/Ia2w3ok0klgoLPND?p=preview" rel="external nofollow">هنا</a>:
</p>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" data-ss1614688784="1" frameborder="no" height="524" loading="lazy" scrolling="no" src="https://codepen.io/Hsoub/embed/zYojaPW?height=524&amp;theme-id=light&amp;default-tab=result" style="width: 100%;" title="JS-p2-mousemove-mouseover-mouseout-mouseenter-mouseleave-ex05">See the Pen JS-p2-mousemove-mouseover-mouseout-mouseenter-mouseleave-ex05 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	جرّب تحريك المؤشّر إلى داخل وخارج خانات الجدول وكذلك بداخلها. بسرعة أو ببطء، لا يهمّ ذلك. لا تُبرَز إلّا <code>&lt;td&gt;</code> ككلّ، بخلاف المثال السابق.
</p>

<h2>
	الملخص
</h2>

<p>
	تناولنا الأحداث <code>mouseover</code> و<code>mouseout</code> و<code>mousemove</code> و<code>mouseenter</code> و<code>mouseleave</code>.
</p>

<p>
	من الجيّد التنبّه لهذه الأمور:
</p>

<ul>
<li>
		قد تتخطّى الحركةُ السريعة للفأرة العناصر البينيّة.
	</li>
	<li>
		تملك الأحداث <code>mouseover/out</code> و<code>mouseenter/leave</code> الخاصيّة الإضافيّة <code>relatedTarget</code>، وهي تمثّل العنصر الذي أتينا منه/إليه، وتكمّل الخاصيّة <code>target</code>.
	</li>
</ul>
<p>
	تقع الأحداث <code>mouseover/out</code> حتى لو ذهبنا من عنصر أبويّ إلى عنصر ابنيّ. يَفترِض المتصفّحُ أنّه يمكن للفأرة أن تكون فوق عنصر واحد فقط في نفس الوقت، وهو العنصر الذي في الأسفل.
</p>

<p>
	تختلف الأحداث <code>mouseenter/leave</code> في هذا الجانب، فهي تقع فقط عندما تأتي الفأرة من/إلى العنصر ككلّ. إضافة إلى ذلك، هي لا تنتشر نحو الأعلى.
</p>

<h2>
	التمارين
</h2>

<h3>
	سلوك التلميحة المحسَّن
</h3>

<p>
	الأهميّة: 5
</p>

<p>
	اكتب شيفرة جافاسكربت لإظهار تلميحة فوق العنصر الذي له السمة <code>data-tooltip</code>. يجب أن تصير قيمة هذه السمة نصّ التلميحة.
</p>

<p>
	يشبه هذا التمرين <a data-ss1614688784="1" href="#" rel="">سلوك التلميحة</a>، لكن يمكن هنا أن تكون العناصر الموسّمة متداخلة، ويحب حينها أن تُعرض التلميحة التي تكون في الأسفل. ويمكن أن تظهر تلميحة واحدة فقط في نفس الوقت. على سبيل المثال:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1221_17" style="">
<span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">data-tooltip</span><span class="pun">=</span><span class="atv">"Here – is the house interior"</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"house"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">data-tooltip</span><span class="pun">=</span><span class="atv">"Here – is the roof"</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"roof"</span><span class="tag">&gt;&lt;/div&gt;</span><span class="pln">
  ...
  </span><span class="tag">&lt;a</span><span class="pln"> </span><span class="atn">href</span><span class="pun">=</span><span class="atv">"https://en.wikipedia.org/wiki/The_Three_Little_Pigs"</span><span class="pln"> </span><span class="atn">data-tooltip</span><span class="pun">=</span><span class="atv">"Read on…"</span><span class="tag">&gt;</span><span class="pln">Hover over me</span><span class="tag">&lt;/a&gt;</span><span class="pln">
</span><span class="tag">&lt;/div&gt;</span></pre>

<p>
	يمكن مشاهدة النتيجة من <a data-ss1614688784="1" href="https://en.js.cx/task/behavior-nested-tooltip/solution/" rel="external nofollow">هنا</a>.
</p>

<p>
	<a data-ss1614688784="1" href="https://plnkr.co/edit/N8Y84iRZJK3JdVjW?p=preview" rel="external nofollow">أنجز التمرين في البيئة التجريبية</a>
</p>

<h3>
	الحل
</h3>

<p>
	<a data-ss1614688784="1" href="https://plnkr.co/edit/Ykgy8Hq2hA92bKxe?p=preview" rel="external nofollow">افتح الحل في البيئة التجريبية</a>
</p>

<h3>
	تلميحة "ذكيّة"
</h3>

<p>
	الأهمية: 5
</p>

<p>
	اكتب دالّة لإظهار تلميحة فوق عنصر ما فقط عندما يحرّك المستخدم الفأرة إلى <em>داخل العنصر</em> وليس <em>عبره</em>.
</p>

<p>
	بعبارة أخرى، إذا حرّك المستخدم الفأرة إلى عنصر ما وتوقّفت هناك، أظهر التلميحة. وإذا حرّكها مرورا به فقط، فلا داعي لذلك، إذ لا أحد يريد ومضات زائدة.
</p>

<p>
	فنيّا، يمكننا قياس سرعة الفأرة فوق العنصر، فإذا كانت بطيئة يمككنا افتراض أنّها أتت "فوق العنصر" وإظهار التلميحة. وإذا كانت سريعة تجاهلناها.
</p>

<p>
	أنشئ كائنا عموميّا <code>new HoverIntent(options)‎</code> لهذا الغرض، له الخيارات <code>options</code> التالية:
</p>

<ul>
<li>
		<code>elem</code> هو العنصر الذي نتتبّعه.
	</li>
	<li>
		<code>over</code> هي الدالّة التي نستدعيها إذا أتت الفأرة إلى العنصر: أي إذا تحرّكت ببطء أو توقّفت فوقه.
	</li>
	<li>
		<code>out</code> هي الدالّة التي نستدعيها إذا غادرت الفأرة العنصر (في حال استُدعيت <code>over</code>).
	</li>
</ul>
<p>
	هذا مثال لاستخدام هذا الكائن للتلميحة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1221_19" style="">
<span class="com">//  تلميحة تجريبيّة</span><span class="pln">
let tooltip </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">createElement</span><span class="pun">(</span><span class="str">'div'</span><span class="pun">);</span><span class="pln">
tooltip</span><span class="pun">.</span><span class="pln">className </span><span class="pun">=</span><span class="pln"> </span><span class="str">"tooltip"</span><span class="pun">;</span><span class="pln">
tooltip</span><span class="pun">.</span><span class="pln">innerHTML </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Tooltip"</span><span class="pun">;</span><span class="pln">

</span><span class="com">// over/out سيتتبّع الكائن الفأرة ويستدعي</span><span class="pln">
</span><span class="kwd">new</span><span class="pln"> </span><span class="typ">HoverIntent</span><span class="pun">({</span><span class="pln">
  elem</span><span class="pun">,</span><span class="pln">
  over</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    tooltip</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">left </span><span class="pun">=</span><span class="pln"> elem</span><span class="pun">.</span><span class="pln">getBoundingClientRect</span><span class="pun">().</span><span class="pln">left </span><span class="pun">+</span><span class="pln"> </span><span class="str">'px'</span><span class="pun">;</span><span class="pln">
    tooltip</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">top </span><span class="pun">=</span><span class="pln"> elem</span><span class="pun">.</span><span class="pln">getBoundingClientRect</span><span class="pun">().</span><span class="pln">bottom </span><span class="pun">+</span><span class="pln"> </span><span class="lit">5</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="str">'px'</span><span class="pun">;</span><span class="pln">
    document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">append</span><span class="pun">(</span><span class="pln">tooltip</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  out</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    tooltip</span><span class="pun">.</span><span class="pln">remove</span><span class="pun">();</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">});</span></pre>

<p>
	يمكن مشاهدة النتيجة من <a data-ss1614688784="1" href="https://en.js.cx/task/hoverintent/solution/" rel="external nofollow">هنا</a>. إذا حرّكت الفأرة فوق "الساعة" بسرعة فلن يحصل شيء، وإذا حرّكتها ببطء أو توقّفت عندها، فستكون هناك تلميحة.
</p>

<p>
	يُرجى التنبّه: لا "تومض" التلميحة عندما يتحرّك المؤشّر بين العناصر الفرعيّة للساعة.
</p>

<p>
	<a data-ss1614688784="1" href="https://plnkr.co/edit/vaC7qQoEslRkWWZ7?p=preview" rel="external nofollow">أنجز التمرين في البيئة التجريبية</a>.
</p>

<h3>
	الحل
</h3>

<p>
	تبدو الخوارزمية بسيطة:
</p>

<ol>
<li>
		أسند معالجات <code>onmouseover/out</code> إلى العنصر. يمكن أيضا استخدام <code>onmouseenter/leave</code> هنا، لكنّها أقلّ عموما، ولن تعمل إذا أدخلنا التفويض.
	</li>
	<li>
		إذا دخل المؤشّر العنصر، ابدأ بقياس السرعة في <code>mousemove</code>.
	</li>
	<li>
		إذا كانت السرعة صغيرة، شغّل <code>over</code>.
	</li>
	<li>
		عند الذهاب إلى خارج العنصر وقد نُفّذت <code>over</code>، شغّل <code>out</code>.
	</li>
</ol>
<p>
	لكن كيف تُقاس السرعة؟
</p>

<p>
	قد تكون أوّل فكرة: شغّل دالّة كلّ <code>100ms</code> وقس المسافة بين الإحداثيات السابقة والجديدة. إذا كانت المسافة صغيرة، فإنّ السرعة صغيرة.
</p>

<p>
	للأسف، لا سبيل للحصول على"الإحداثيّات الحاليّة للفأرة" في جافاسكربت. لا وجود لدالّة مثل <code>getCurrentMouseCoordinates()‎</code>.
</p>

<p>
	السبيل الوحيد للحصول على الإحداثيّات هو الإنصات لأحداث الفأرة، مثل <code>mousemove</code> وأخذ الإحداثيّات من كائن الحدث.
</p>

<p>
	لنضع إذًا معالجًا للحدث <code>mousemove</code>، لتتبّع الإحداثيّات وتذكّرها. ثمّ لمقارنتها مرّة كلّ <code>100ms</code>.
</p>

<p>
	ملاحظة: تَستخدم اختباراتُ الحلّ <code>dispatchEvent</code> لرؤية ما إذا كانت التلميحة تعمل جيّدا.
</p>

<p>
	<a data-ss1614688784="1" href="https://plnkr.co/edit/n8OtYNISvRNcwCcm?p=preview" rel="external nofollow">شاهد الحل في البيئة التجريبية</a>.
</p>

<p>
	ترجمة -وبتصرف- للمقال <a data-ss1614688784="1" href="https://javascript.info/mousemove-mouseover-mouseout-mouseenter-mouseleave" rel="external nofollow">Moving the mouse: mouseover/out, mouseenter/leave</a> من سلسلة <a data-ss1614688784="1" href="https://javascript.info/ui" rel="external nofollow">Browser: Document, Events, Interfaces</a> لصاحبها Ilya Kantor
</p>
]]></description><guid isPermaLink="false">1152</guid><pubDate>Sat, 13 Mar 2021 13:09:00 +0000</pubDate></item><item><title>&#x623;&#x62D;&#x62F;&#x627;&#x62B; &#x627;&#x644;&#x641;&#x623;&#x631;&#x629; &#x641;&#x64A; &#x627;&#x644;&#x645;&#x62A;&#x635;&#x641;&#x62D; &#x648;&#x627;&#x644;&#x62A;&#x639;&#x627;&#x645;&#x644; &#x645;&#x639;&#x647;&#x627; &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A;</title><link>https://academy.hsoub.com/programming/javascript/%D8%A3%D8%AD%D8%AF%D8%A7%D8%AB-%D8%A7%D9%84%D9%81%D8%A3%D8%B1%D8%A9-%D9%81%D9%8A-%D8%A7%D9%84%D9%85%D8%AA%D8%B5%D9%81%D8%AD-%D9%88%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9%D9%87%D8%A7-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r1151/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_03/603e2f665f8dc_-------.png.f0781e830dc0c8ff7dacc4ba0f4d8e88.png" /></p>

<p>
	سنتناول في هذا المقال أحداث الفأرة وخاصّياتها بمزيد من التفصيل.
</p>

<p>
	يُرجى التنبه: لا تأتي هذه الأحداث فقط من "الأجهزة ذوات الفأرة"، ولكن من أجهزة أخرى أيضًا مثل الهواتف والأجهزة اللوحيّة، حيث تُحاكى فيها هذه الأحداث لتحقيق التوافق.
</p>

<h2>
	أنواع أحداث الفأرة
</h2>

<p>
	سبق وأن رأينا بعض هذه الأحداث:
</p>

<ul>
<li>
		<strong><code>mousedown/mouseup</code></strong>: يحدث عندما يُنقر / يُحرَّر زرّ الفأرة فوق عنصر ما.
	</li>
	<li>
		<strong><code>mouseover/mouseout</code></strong>: يحدث عندما يبلغ / يغادر مؤشّر الفأرة عنصرا ما.
	</li>
	<li>
		<strong><code>mousemove</code></strong>: يحدث كلّما تحرّك مؤشّر الفأرة فوق عنصر ما.
	</li>
	<li>
		<strong><code>click</code></strong>: يحدث بعد حدوث <code>mousedown</code> ثم <code>mouseup</code> فوق نفس العنصر باستخدام الزرّ الأيسر للفأرة.
	</li>
	<li>
		<strong><code>dblclick</code></strong>؛ يحدث بعد النقر مرّتين على نفس العنصر خلال إطار زمنيّ قصير. يندر استخدامه هذه الأيام.
	</li>
	<li>
		<strong><code>contextmenu</code></strong>: يحدث عندما يُضغط الزرّ الأيمن للفأرة. وبما أنّ هناك طرقا أخرى لفتح القائمة المنبثقة، كاستخدام زرّ خاصّ في لوحة المفاتيح مثلا، فإنّه يحدث عند ذلك أيضا، ولا يُعدّ بذلك من الأحداث المختصّة بالفأرة على وجه الدقّة.
	</li>
</ul>
<p>
	هناك العديد من الأحداث الأخرى أيضا، سنتطرّق إليها لاحقا.
</p>

<h2>
	ترتيب الأحداث
</h2>

<p>
	⁧⁧⁧⁧⁧⁧⁧⁧⁧⁧⁧⁧⁧⁧⁧⁧⁧⁧ مثلما يمكن أن تلاحظ في القائمة أعلاه، قد يؤدّي فعل واحد للمستخدم إلى وقوع عدّة أحداث. على سبيل المثال، يؤدّي النقر بالزرّ اﻷيسر أوّلا إلى حدوث <code>mousedown</code> عند الضغط على الزرّ، ثم إلى حدوث <code>mouseup</code> و<code>click</code> عند تحريره.
</p>

<p>
	في الحالات التي يبتدئُ فيها فعلٌ واحد عدّةَ أحداث، فإنّ ترتيبها يكون ثابتا. بمعنى أن المعالجات نُستدعى هنا حسب الترتيب <code>mousedown</code> ⁧-&gt; <code>mouseup</code> ⁧-&gt; <code>click</code>.
</p>

<p>
	إليك <a data-ss1614688084="1" href="https://codepen.io/Hsoub/pen/mdOLKbv" rel="external nofollow">التجربة الحيّة</a> التالية لمثال تُسجَّل فيه جميع أحداث الفأرة، وإذا كان هناك فارق بأكثر من ثانية بينها ستُفصل بخطّ أفقيّ. يمكنك أيضا رؤية الخاصّيّة <code>button</code> التي تمكّن من اكتشاف زرّ الفأرة، وسيُشرح ذلك في أسفله:
</p>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" data-ss1614688084="1" frameborder="no" height="314" loading="lazy" scrolling="no" src="https://codepen.io/Hsoub/embed/mdOLKbv?height=314&amp;theme-id=light&amp;default-tab=result" style="width: 100%;" title="JS-p2-mouse-events-basics-ex01">See the Pen JS-p2-mouse-events-basics-ex01 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<h2>
	زر الفأرة
</h2>

<p>
	تكون للأحداث المتعلّقة بالنقر دائما الخاصّيّة <code>button</code>، التي تمكّن من معرفة الزرّ الذي ضُغط بالضبط. قد لا نحتاج إلى استعمالها في العادة مع اﻷحداث <code>click</code> و<code>contextmenu</code>، لأّن اﻷوّل يحدث فقط عند النقر باليسار، بينما يحدث اﻷخير فقط عند النقر باليمين. لكن في المقابل، قد تحتاج معالجات الأحداث <code>mousedown</code> و<code>mouseup</code> إلى الخاصّيّة <code>event.button</code>، لأنّ تلك اﻷحداث قد تقع عند النقر على أيٍّ من الأزرار، فتمكّن <code>button</code> من التمييز بين "mousedown اﻷيمن" و"mousedown اﻷيسر".
</p>

<p>
	يمكن أن تأخذ الخاصّيّة <code>button</code> القيم التالية:
</p>

<table>
<thead><tr>
<th>
				حالة الزرّ
			</th>
			<th>
				<code>event.button</code>
			</th>
		</tr></thead>
<tbody>
<tr>
<td>
				الزرّ اﻷيسر (اﻷوليّ)
			</td>
			<td>
				0
			</td>
		</tr>
<tr>
<td>
				الزرّ اﻷوسط (الملحق)
			</td>
			<td>
				1
			</td>
		</tr>
<tr>
<td>
				الزرّ اﻷيمن (الثانويّ)
			</td>
			<td>
				2
			</td>
		</tr>
<tr>
<td>
				الزرّ X1 (الخلف)
			</td>
			<td>
				3
			</td>
		</tr>
<tr>
<td>
				الزرّ X2 (اﻷمام)
			</td>
			<td>
				4
			</td>
		</tr>
</tbody>
</table>
<style type="text/css">
table {
    width: 100%;
}

thead {
    vertical-align: middle;

    text-align: center;
} 

td, th {
    border: 1px solid #dddddd;
    text-align: right;
    padding: 8px;
    text-align: inherit;

}
tr:nth-child(even) {
    background-color: #dddddd;
}</style>
<p>
	ليس لدى معظم أجهزة الفأرة سوى الزرّين اﻷيمن واﻷيسر، فتكون القيم الممكنة <code>0</code> أو <code>2</code>. تولّد اﻷجهزة اللمسيّة أيضا مثل هذه اﻷحداث عندما ينقر أحدهم عليها.
</p>

<p>
	ثم إنّ هناك الخاصّيّة <code>event.buttons</code> التي تعبّر عن جميع الأزرار المضغوطة حاليّا بعدد صحيح، يكون ناتج مجموع قيم تلك اﻷزرار. يندر جدّا استخدام هذه الخاصّيّة في الواقع، لكن يمكنك أن تجد المزيد من التفاصيل حولها من <a data-ss1614688084="1" href="https://developer.mozilla.org/en-US/docs/Web/api/MouseEvent/buttons" rel="external nofollow">MDN</a> إن حصل واحتجت لها.
</p>

<hr>
<p>
	<strong>تنبيه: خاصّيّة <code>event.which</code> المندثرة</strong>
</p>

<p>
	قد تستعمل الشيفراتُ القديمة الخاصّيّة <code>event.which</code> وهي طريقة قديمة وغير قياسية للحصول على الزرّ، ويمكن أن تأخذ القيم التالية:
</p>

<ul>
<li>
		<code>event.which == 1</code> -- الزرّ اﻷيسر،
	</li>
	<li>
		<code>event.which == 2</code> -- الزرّ اﻷوسط،
	</li>
	<li>
		<code>event.which == 3</code> -- الزرّ اﻷيمن.
	</li>
</ul>
<hr>
<p>
	حاليّا، تُعدّ <code>event.which</code> مهملة (deprecated)، ولا ينبغي استعمالها.
</p>

<h2>
	مفاتيح التبديل: shift و alt و ctrl و meta
</h2>

<p>
	تحتوي جميع أحداث الفأرة على المعلومات الخاصّة بمفاتيح التبديل المضغوطة. فللكائن <code>event</code> الخاصّيّات التالية:
</p>

<ul>
<li>
		<code>shiftKey</code>: المفتاح <code>Shift</code>
	</li>
	<li>
		<code>altKey</code>: المفتاح <code>Alt</code> (أو المفتاح <code>Opt</code> في ماك)
	</li>
	<li>
		<code>ctrlKey</code>: المفتاح <code>Ctrl</code>
	</li>
	<li>
		<code>metaKey</code>: المفتاح <code>Cmd</code> في ماك
	</li>
</ul>
<p>
	تكون قيم هذه الخاصّيّات <code>true</code> إذا كان المفتاح المقابل لها مضغوطا عند وقوع الحدث. فعلى سبيل المثال، لا يعمل الزرّ أسفله إلا عند النقر مع الضغط على المفاتيح <code>Alt</code> و<code>Shift</code> معا:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_8888_8" style="">
<span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"button"</span><span class="tag">&gt;</span><span class="pln">Alt+Shift+Click on me!</span><span class="tag">&lt;/button&gt;</span><span class="pln">

</span><span class="tag">&lt;script&gt;</span><span class="pln">
  button</span><span class="pun">.</span><span class="pln">onclick </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">event</span><span class="pun">.</span><span class="pln">altKey </span><span class="pun">&amp;&amp;</span><span class="pln"> event</span><span class="pun">.</span><span class="pln">shiftKey</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      alert</span><span class="pun">(</span><span class="str">'Hooray!'</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">};</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" data-ss1614688084="1" frameborder="no" height="143" loading="lazy" scrolling="no" src="https://codepen.io/Hsoub/embed/jOVxKbq?height=143&amp;theme-id=light&amp;default-tab=result" style="width: 100%;" title="JS-p2-mouse-events-basics-ex02">See the Pen JS-p2-mouse-events-basics-ex02 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<hr>
<p>
	<strong>تنبيه: عادة ما يُستعمل المفتاح <code>Cmd</code> بدل <code>Ctrl</code> في ماك</strong>
</p>

<p>
	توجد في ويندوز ولينكس مفاتيح التبديل <code>Alt</code> و<code>Shift</code> و<code>Ctrl</code>. كما يوجد في ماك المفتاح الإضافيّ <code>Cmd</code> الذي تقابله الخاصّيّة <code>metaKey</code>.
</p>

<p>
	في معظم التطبيقات، عندما يُستعمل في ويندوز ولينكس المفتاح <code>Ctrl</code> فإنّ في ماك يُستعمل المفتاح <code>Cmd</code>. بمعنى أنّه عندما يضغط مستخدم ويندوز على المفتاحين <code>Ctrl</code> و<code>Enter</code> أو <code>Ctrl</code> و<code>A</code>، فإنّ من المفترض أن يضغط مستخدم ماك على المفتاحين <code>Cmd</code> و<code>Enter</code> أو <code>Cmd</code> و<code>A</code>، وهكذا.
</p>

<p>
	فإذا أردت أن تعتمد الجمع بين <code>Ctrl</code> والنقر مثلا، فمن المعقول استخدام الجمع بين <code>Cmd</code> والنقر في ماك. فذلك أريح لمستخدمي ماك.
</p>

<p>
	حتى وإن فضّلنا اضطرار مستخدمي ماك إلى الجمع بين <code>Ctrl</code> والنقر -- ذلك صعب بعض الشيء، فإنّ المشكلة أن النقر باليسار مع الضغط على <code>Ctrl</code> في نظام التشغيل ماك يُفهم على أنّه نقر باليمين، ويؤدّي إلى توليد الحدث <code>contextmenu</code>، وليس <code>click</code> كما في ويندوز ولينكس.
</p>

<p>
	فإذا أردنا أن نحرص على راحة مستخدمي جميع أنظمة التشغيل، فينبغي أن نفحص كلتى الخاصّيتين <code>ctrlKey</code> و<code>metaKey</code>. ما يعني ذلك في شيفرة جافاسكربت هو أن نتحقّق <code>if (event.ctrlKey || event.metaKey)‎</code>.
</p>

<hr>
<hr>
<p>
	<strong>تنبيه: هناك أيضا أجهزة محمولة</strong>
</p>

<p>
	يُعدّ الجمع بين المفاتيح إضافة جيّدة في سير العمل. فإذا كان الزائر يستخدم لوحة المفاتيح، فستعمل بشكل جيّد. لكن إذ لم يكن جهازه متضمّنا لها، فلابدّ إذا من وجود سبيل للعمل دون مفاتيح التبديل.
</p>

<hr>
<h2>
	الإحداثيات: clientX/Y وpageX/Y
</h2>

<p>
	تقدّم جميع أحداث الفأرة نوعين من الإحداثيّات:
</p>

<ol>
<li>
		بالنسبة إلى النافذة: <code>clientX</code> و<code>clientY</code>.
	</li>
	<li>
		بالنسبة إلى المستند: <code>pageX</code> و<code>pageY</code>.
	</li>
</ol>
<p>
	باختصار، تُحتسب الإحداثيّات بالنسبة إلى النافذة <code>pageX/Y</code> ابتداءً من الزاوية العليا من اليسار للمستند، ولا تتغيّر عند تمرير (scroll) الصفحة، بينما تُحتسب <code>clientX/Y</code> ابتداءً من الزاوية العليا من اليسار للنافذة الحاليّة وتتغيّر عند تمرير الصفحة.
</p>

<p>
	على سبيل المثال، إذا كانت لدينا نافذة قياسها 500x500، والفأرة موجودة في الزاوية العليا من اليسار، فإنّ قيمتا <code>clientX</code> و<code>clientY</code> هي <code>0</code>، مهما مُرّرت الصفحة. بينما إذا كانت الفأرة في المنتصف، فإن قيمتا <code>clientX</code> و<code>clientY</code> هي <code>250</code>، أيًّا كان مكانها في المستند. وهما بهذا الاعتبار متشابهتان مع <code>position:fixed</code>.
</p>

<p>
	حرّك الفأرة فوق حقل المُدخل لرؤية <code>clientX/clientY</code> (المثال موجود داخل <code>iframe</code>، لذا فإنّ الإحداثيّات منسوبة إلى <code>iframe</code>).
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_8888_10" style="">
<span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">onmousemove</span><span class="pun">=</span><span class="atv">"</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">value</span><span class="pun">=</span><span class="pln">event</span><span class="pun">.</span><span class="pln">clientX</span><span class="pun">+</span><span class="str">':'</span><span class="pun">+</span><span class="pln">event</span><span class="pun">.</span><span class="pln">clientY</span><span class="atv">"</span><span class="pln"> </span><span class="atn">value</span><span class="pun">=</span><span class="atv">"Mouse over me"</span><span class="tag">&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" data-ss1614688084="1" frameborder="no" height="145" loading="lazy" scrolling="no" src="https://codepen.io/Hsoub/embed/qBqYKOY?height=145&amp;theme-id=light&amp;default-tab=result" style="width: 100%;" title="JS-p2-mouse-events-basics-ex03">See the Pen JS-p2-mouse-events-basics-ex03 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<h2>
	تجنب التحديد مع mousedown
</h2>

<p>
	للنقر المزدوج بالفأرة أثر جانبيّ قد يكون مزعجا في بعض الواجهات، ألا وهو تحديد النصّ. على سبيل المثال، يؤدّي النقر المزدوج على النصّ أدناه إلى تحديده بالإضافة تشغيل المعالج المسند إليه:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_8888_12" style="">
<span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">ondblclick</span><span class="pun">=</span><span class="atv">"</span><span class="pln">alert</span><span class="pun">(</span><span class="str">'dblclick'</span><span class="pun">)</span><span class="atv">"</span><span class="tag">&gt;</span><span class="pln">Double-click me</span><span class="tag">&lt;/span&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" data-ss1614688084="1" frameborder="no" height="145" loading="lazy" scrolling="no" src="https://codepen.io/Hsoub/embed/abBGKdE?height=145&amp;theme-id=light&amp;default-tab=result" style="width: 100%;" title="JS-p2-mouse-events-basics-ex04">See the Pen JS-p2-mouse-events-basics-ex04 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	وإذا ضغط أحدهم زرّ الفأرة اﻷيمن، وحرك الفأرة دون تحريره، فسيعمل ذلك أيضا على تحديد النص، ولا يُرغب في ذلك غالبا.
</p>

<p>
	هناك عدّة طرق لتجنُّب التحديد، يمكنك الاطّلاع عليها في مقال <a data-ss1614688084="1" href="#" rel="">التحديد والمدى</a>. لكن في هذه الحالة خاصّة، أنسب طريقة لذلك هي منع فعل المتصفّح عند <code>mousedown</code>، ليحول ذلك دون حصول هذه التحديدات:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_8888_14" style="">
<span class="pln">Before...
</span><span class="tag">&lt;b</span><span class="pln"> </span><span class="atn">ondblclick</span><span class="pun">=</span><span class="atv">"</span><span class="pln">alert</span><span class="pun">(</span><span class="str">'Click!'</span><span class="pun">)</span><span class="atv">"</span><span class="pln"> </span><span class="atn">onmousedown</span><span class="pun">=</span><span class="atv">"</span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">false</span><span class="atv">"</span><span class="tag">&gt;</span><span class="pln">
  Double-click me
</span><span class="tag">&lt;/b&gt;</span><span class="pln">
...After</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" data-ss1614688084="1" frameborder="no" height="146" loading="lazy" scrolling="no" src="https://codepen.io/Hsoub/embed/JjbvZGL?height=146&amp;theme-id=light&amp;default-tab=result" style="width: 100%;" title="JS-p2-mouse-events-basics-ex05">See the Pen JS-p2-mouse-events-basics-ex05 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	لا يُحدَّد العنصر ذو الخطّ العريض الآن عند النقر المزدوج عليه، ولا يؤدّي النقر عليه باليسار إلى ابتداء تحديده أيضا. لكن يُرجى التنبّه: يبقى النصّ داخله قابلا للتحديد، إذا ابتُدئ التحديد قبل النصّ أو بعده، لا عليه مباشرة، ولا بأس في ذلك بالنسبة للمستخدمين عادة.
</p>

<hr>
<p>
	<strong>ملاحظة: منع النسخ</strong>
</p>

<p>
	إذا أردنا أن نعطّل تحديد النصّ لحماية محتوى صفحتنا من النسخ واللصق، فيمكننا عندها استعمال حدث آخر: <code>oncopy</code>.
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_8888_16" style="">
<span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">oncopy</span><span class="pun">=</span><span class="atv">"</span><span class="pln">alert</span><span class="pun">(</span><span class="str">'Copying forbidden!'</span><span class="pun">);</span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">false</span><span class="atv">"</span><span class="tag">&gt;</span><span class="pln">
  Dear user,
  The copying is forbidden for you.
  If you know JS or HTML, then you can get everything from the page source though.
</span><span class="tag">&lt;/div&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" data-ss1614688084="1" frameborder="no" height="149" loading="lazy" scrolling="no" src="https://codepen.io/Hsoub/embed/qBqYKbY?height=149&amp;theme-id=light&amp;default-tab=result" style="width: 100%;" title="JS-p2-mouse-events-basics-ex06">See the Pen JS-p2-mouse-events-basics-ex06 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	فلو حاولت نسخ جزء من النصّ الذي بداخل <code>&lt;div&gt;</code>، فلن يعمل ذلك، ﻷن الفعل الافتراضيّ <code>oncopy</code> قد مُنع. يمكن للمستخدم بالتأكيد الوصول إلى مصدر HTML، وأخذ المحتوى من هناك، لكن لا يُحسن الجميع فعل ذلك.
</p>

<hr>
<h2>
	الملخص
</h2>

<p>
	لأحداث الفأرة الخاصّيّات التالية:
</p>

<ul>
<li>
		الزرّ: <code>button</code>.
	</li>
	<li>
		مفاتيح التبديل: (<code>true</code> عند الضغط عليها): <code>altKey</code> و<code>ctrlKey</code> و<code>shiftKey</code> و<code>metaKey</code> (ماك).
		<ul>
<li>
				إذا كنت تودّ اعتماد <code>Ctrl</code>، لا تنس مستخدمي ماك، إذ يستعملون عادة <code>Cmd</code>، فيُفضّل إذًا أن نتحقّق <code>if (e.metaKey || e.ctrlKey)‎</code>.
			</li>
		</ul>
</li>
	<li>
		الإحداثيّات بالنسبة للنافذة: <code>clientX/clientY</code>.
	</li>
	<li>
		الإحداثيّات بالنسبة للمستند: <code>pageX/pageY</code>.
	</li>
</ul>
<p>
	فعل المتصفح الافتراضيّ عند <code>mousedown</code> هو تحديد النصّ، فإذا لم يكن مناسبا في الواجهة، ينبغي منعه.
</p>

<p>
	في المقال التالي سنتناول المزيد من التفاصيل حول اﻷحداث التي تلي حركة المؤشّر وكيفية تتبّع تغيير العناصر التي تحته.
</p>

<h2>
	التمارين
</h2>

<h3>
	قائمة قابلة للتحديد
</h3>

<p>
	اﻷهمية: 5
</p>

<p>
	أنشئ قائمة تكون عناصرها قابلة للتحديد، كما في مديري الملفّات.
</p>

<ul>
<li>
		بالنقر على عنصر من القائمة يُحدَّد ذلك العنصر فقط (بإضافة الصنف <code>selected‎.</code>) ويزال التحديد عن بقيّة العناصر.
	</li>
	<li>
		إذا تمّ النقر مع المفتاح <code>Ctrl</code> (<code>‏Cmd</code> بالنسبة لماك)، فإنّ التحديد ينقلب (toggled) في ذلك العنصر، ولا تتغيّر بقيّة العناصر.
	</li>
</ul>
<p>
	يمكن مشاهدة المثال من <a data-ss1614688084="1" href="https://en.js.cx/task/selectable-list/solution/" rel="external nofollow">هنا</a>.
</p>

<p>
	<strong>ملاحظة</strong>: في هذا التمرين، يمكننا افتراض أنّ عناصر القائمة مكوّنة من نصّ فقط. ليست هناك وسوم متداخلة.
</p>

<p>
	<strong>ملاحظة</strong> أخرى: امنع تحديد المتصفّح اﻷصيل للنصوص عند النقر عليها.
</p>

<p>
	<a data-ss1614688084="1" href="https://plnkr.co/edit/gUrAWTnZOfpP1vAp?p=preview&amp;preview" rel="external nofollow">أنجز التمرين في البيئة التجريبية</a>
</p>

<h3>
	الحل
</h3>

<p>
	<a data-ss1614688084="1" href="https://plnkr.co/edit/5olx4aoq3eG1HIqa?p=preview" rel="external nofollow">افتح الحل في البيئة التجريبية</a>
</p>

<p>
	ترجمة -وبتصرف- للمقال <a data-ss1614688084="1" href="https://javascript.info/mouse-events-basics" rel="external nofollow">Mouse events</a> من سلسلة <a data-ss1614688084="1" href="https://javascript.info/ui" rel="external nofollow">Browser: Document, Events, Interfaces</a> لصاحبها Ilya Kantor
</p>
]]></description><guid isPermaLink="false">1151</guid><pubDate>Tue, 09 Mar 2021 13:02:00 +0000</pubDate></item><item><title>&#x625;&#x646;&#x634;&#x627;&#x621; &#x623;&#x62D;&#x62F;&#x627;&#x62B; &#x645;&#x62E;&#x635;&#x635;&#x629; &#x641;&#x64A; &#x627;&#x644;&#x645;&#x62A;&#x635;&#x641;&#x62D; &#x639;&#x628;&#x631; &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A;</title><link>https://academy.hsoub.com/programming/javascript/%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%A3%D8%AD%D8%AF%D8%A7%D8%AB-%D9%85%D8%AE%D8%B5%D8%B5%D8%A9-%D9%81%D9%8A-%D8%A7%D9%84%D9%85%D8%AA%D8%B5%D9%81%D8%AD-%D8%B9%D8%A8%D8%B1-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r1144/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_02/5.png.5e176b92024ce92745112b5b8c3e8b75.png" /></p>

<p>
	لا يمكننا فقط إسناد معالجات للأحداث من خلال جافاسكربت، ولكن يمكننا أيضا توليد أحداث مخصّصة.
</p>

<p>
	يُمكن استعمال الأحداث المخصّصة لإنشاء "مكوّنات رسوميّة". على سبيل المثال، يمكن للعنصر الجذر في قائمةٍ تعمل بواسطة جافاسكربت افتعال أحداثٍ تُنبئ بما يحصل مع القائمة: <code>open</code> (عند فتح القائمة)، <code>select</code> (عند تحديد عنصر) وهكذا. يمكن أن تنصت شيفرة أخرى لهذه الأحداث وتراقب ماذا يحصل مع القائمة.
</p>

<p>
	لا يمكننا فقط توليد أحداث جديدة كليّا، نخترعها لأغراضنا الخاصّة، ولكن يمكن أيضا توليد اﻷحداث المضمّنة، مثل <code>click</code> و <code>mousedown</code> إلى غير ذلك. قد يساعد ذلك عند إجراء الاختبارات الآليّة.
</p>

<h2>
	باني الأحداث
</h2>

<p>
	تشكّل أصناف الأحداث المضمّنة سُلّميّة مشابهة لسلّميّة أصناف عناصر DOM. يكون الجذر فيها هو الصنف المُضمّن <a data-ss1613985682="1" href="http://www.w3.org/TR/dom/#event" rel="external nofollow">Event</a>. ويمكننا إنشاء كائنات منها بهذه الطريقة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2146_7" style="">
<span class="pln">let event </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Event</span><span class="pun">(</span><span class="pln">type</span><span class="pun">[,</span><span class="pln"> options</span><span class="pun">]);</span></pre>

<p>
	الوسائط:
</p>

<ul>
<li>
		<em>type</em> -- نوع الحدث، ويكون سلسلة نصيّة مثل <code>"click"</code> أو إذا كان خاصّا بنا مثل <code>"my-event"</code>.
	</li>
	<li>
		<em>options</em> -- كائن بخاصيتين اختياريتين:
	</li>
	<li>
		<code>bubbles: true/false</code> -- إذا كانت <code>true</code>، فإنّ الحدث ينتشر نحو الأعلى.
	</li>
	<li>
		<code>cancelable: true/false</code>: إذا كانت <code>true</code>، فمن الممكن منع "الفعل الافتراضي". سنرى لاحقًا ما يعني ذلك للأحداث المخصّصة.
	</li>
</ul>
<p>
	تكون قيمة كلتيهما <code>false</code> افتراضيّا: <code>{bubbles: false, cancelable: false}</code>.
</p>

<h2>
	dispatchEvent
</h2>

<p>
	بعد إنشاء كائن الحدث، نستطيع أن "نجريه" على عنصرٍ ما بواسطة الاستدعاء <code>elem.dispatchEvent(event)‎</code>.
</p>

<p>
	تستجيب المعالجات له حينها كما لو كان حدث متصفّح عادي. وإذا كان الحدث قد أنشئ وله الراية <code>bubbles</code>، فإنّه ينتشر نحو الأعلى.
</p>

<p>
	ابتُدِئ الحدث <code>click</code> في المثال أدناه من خلال جافاسكربت. يعمل المعالج بنفس الطريقة كما لو أن الزرّ قد نُقر بالفعل:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_2146_9" style="">
<span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"elem"</span><span class="pln"> </span><span class="atn">onclick</span><span class="pun">=</span><span class="atv">"</span><span class="pln">alert</span><span class="pun">(</span><span class="str">'Click!'</span><span class="pun">);</span><span class="atv">"</span><span class="tag">&gt;</span><span class="pln">Autoclick</span><span class="tag">&lt;/button&gt;</span><span class="pln">

</span><span class="tag">&lt;script&gt;</span><span class="pln">
  let event </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Event</span><span class="pun">(</span><span class="str">"click"</span><span class="pun">);</span><span class="pln">
  elem</span><span class="pun">.</span><span class="pln">dispatchEvent</span><span class="pun">(</span><span class="pln">event</span><span class="pun">);</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" data-ss1613985682="1" frameborder="no" height="182" loading="lazy" scrolling="no" src="https://codepen.io/Hsoub/embed/preview/MWbEvGq?height=182&amp;theme-id=light&amp;default-tab=result" style="width: 100%;" title="JS-p2-dispatch-events -ex1">See the Pen JS-p2-dispatch-events -ex1 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<hr>
<p>
	<strong>ملاحظة: event.isTrusted</strong>
</p>

<p>
	هناك طريقة لمعرفة إذا كان الحدث "حقيقيّا" من المستخدم أو مولّدًا بواسطة سكربت. تكون قيمة الخاصيّة <code>event.isTrusted</code> هي <code>true</code> للأحداث التي تأتي من أفعال حقيقيّة للمستخدم و تكون <code>false</code> للأحداث المولّدة بواسطة سكربت.
</p>

<hr>
<h2>
	مثال عن الانتشار نحو الأعلى
</h2>

<p>
	يمكننا إنشاء حدث منتشر نحو الأعلى باسم <code>"hello"</code> والتقاطه في <code>document</code>. كلّ ما نحتاجه هو إعطاء <code>bubbles</code> القيمة <code>true</code>:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_2146_11" style="">
<span class="tag">&lt;h1</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"elem"</span><span class="tag">&gt;</span><span class="pln">Hello from the script!</span><span class="tag">&lt;/h1&gt;</span><span class="pln">

</span><span class="tag">&lt;script&gt;</span><span class="pln">
  </span><span class="com">// ... document الالتقاط على مستوى</span><span class="pln">
  document</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"hello"</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="com">// (1)</span><span class="pln">
    alert</span><span class="pun">(</span><span class="str">"Hello from "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> event</span><span class="pun">.</span><span class="pln">target</span><span class="pun">.</span><span class="pln">tagName</span><span class="pun">);</span><span class="pln"> </span><span class="com">// Hello from H1</span><span class="pln">
  </span><span class="pun">});</span><span class="pln">

  </span><span class="com">// elem الإرسال من ...</span><span class="pln">
  let event </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Event</span><span class="pun">(</span><span class="str">"hello"</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">bubbles</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">});</span><span class="pln"> </span><span class="com">// (2)</span><span class="pln">
  elem</span><span class="pun">.</span><span class="pln">dispatchEvent</span><span class="pun">(</span><span class="pln">event</span><span class="pun">);</span><span class="pln">

  </span><span class="com">// و يظهر الرسالة document سيشتغل المعالج المسند إلى</span><span class="pln">

</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" data-ss1613985682="1" frameborder="no" height="207" loading="lazy" scrolling="no" src="https://codepen.io/Hsoub/embed/preview/ExNwvLJ?height=207&amp;theme-id=light&amp;default-tab=result" style="width: 100%;" title="JS-p2-dispatch-events -ex2">See the Pen JS-p2-dispatch-events -ex2 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	ملاحظات:
</p>

<ol>
<li>
		يجب أن نستخدم <code>addEventListener</code> لأحداثنا المخصصة، لأن <code>on&lt;event&gt;‎</code> توجد فقط للأحداث المضمّنة، فلا تعمل <code>document.onhello</code> مثلا.
	</li>
	<li>
		يجب وضع <code>bubbles:true</code>، وإلا فلن ينتشر الحدث نحو الأعلى.
	</li>
</ol>
<p>
	آلية الانتشار نحو الأعلى هي نفسها للأحداث المُضمّنة (<code>click</code>) والمخصصة (<code>hello</code>). هناك أيضا مرحلتا الانتشار نحو الأعلى والانتشار نحو الأسفل.
</p>

<h2>
	MouseEvent و KeyboardEvent وغيرهما
</h2>

<p>
	هذه قائمة قصيرة لأصناف أحداث واجهة المستخدم مأخوذة من <a data-ss1613985682="1" href="https://www.w3.org/TR/uievents" rel="external nofollow">مواصفة أحداث واجهة المستخدم</a>:
</p>

<ul>
<li>
		<p>
			<code>UIEvent</code>
		</p>
	</li>
	<li>
		<p>
			<code>FocusEvent</code>
		</p>
	</li>
	<li>
		<p>
			<code>MouseEvent</code>
		</p>
	</li>
	<li>
		<p>
			<code>WheelEvent</code>
		</p>
	</li>
	<li>
		<p>
			<code>KeyboardEvent</code>
		</p>
	</li>
	<li>
		<p>
			…
		</p>
	</li>
</ul>
<p>
	ينبغي أن نستخدمها عوضا عن <code>new Event</code> إذا أردنا إنشاء هذه الأحداث. على سبيل المثال، <code>new MouseEvent("click")‎</code>.
</p>

<p>
	يمكّن الباني المناسب من تحديد خاصيّات قياسية تتعلّق بنوع الحدث ذاك. مثل <code>clientX/clientY</code> لأحداث المؤشر:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2146_13" style="">
<span class="pln">let event </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">MouseEvent</span><span class="pun">(</span><span class="str">"click"</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  bubbles</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
  cancelable</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
  clientX</span><span class="pun">:</span><span class="pln"> </span><span class="lit">100</span><span class="pun">,</span><span class="pln">
  clientY</span><span class="pun">:</span><span class="pln"> </span><span class="lit">100</span><span class="pln">
</span><span class="pun">});</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln">event</span><span class="pun">.</span><span class="pln">clientX</span><span class="pun">);</span><span class="pln"> </span><span class="com">// 100</span></pre>

<p>
	يرجى التنبه: لا يتيح الباني العام <code>Event</code> ذلك.
</p>

<p>
	لنجرّب:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2146_15" style="">
<span class="pln">let event </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Event</span><span class="pun">(</span><span class="str">"click"</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  bubbles</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln"> </span><span class="com">//  cancelable و bubbles فقط  </span><span class="pln">
  cancelable</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln"> </span><span class="com">// Event تعملان في الباني</span><span class="pln">
  clientX</span><span class="pun">:</span><span class="pln"> </span><span class="lit">100</span><span class="pun">,</span><span class="pln">
  clientY</span><span class="pun">:</span><span class="pln"> </span><span class="lit">100</span><span class="pln">
</span><span class="pun">});</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln">event</span><span class="pun">.</span><span class="pln">clientX</span><span class="pun">);</span><span class="pln"> </span><span class="com">// تُهمل الخاصّية غير المعروفة ،undefined</span></pre>

<p>
	في الحقيقة، يمكننا الاحتيال على ذلك بإسناد <code>event.clientX=100</code> مباشرة بعد إنشائه. فيؤول الأمر إلى المناسبة والالتزام بالقواعد. يكون نوع الأحداث التي يولّدها المتصفّح صحيحًا على الدوام.
</p>

<p>
	توجد القائمة الشاملة لمختلف أحداث واجهة المستخدم في المواصفة، على سبيل المثال، <a data-ss1613985682="1" href="https://www.w3.org/TR/uievents/#mouseevent" rel="external nofollow">MouseEvent</a>.
</p>

<h2>
	الأحداث المخصصة
</h2>

<p>
	بالنسبة لأنواع الأحداث الخاصّة بنا والجديدة كليّا مثل <code>"hello"</code> علينا أن نستخدم <code>new CustomEvent</code>. فنيّا، <a data-ss1613985682="1" href="https://dom.spec.whatwg.org/#customevent" rel="external nofollow">CustomEvent</a> هي نفس <code>Event</code> لكن مع استثناء وحيد.
</p>

<p>
	في الوسيط الثاني (object) يمكننا إضافة خاصيّة أخرى <code>detail</code> من أجل أيّة معلومات مخصصّة نودّ تمريرها مع الحدث. على سبيل المثال:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_2146_17" style="">
<span class="tag">&lt;h1</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"elem"</span><span class="tag">&gt;</span><span class="pln">Hello for John!</span><span class="tag">&lt;/h1&gt;</span><span class="pln">

</span><span class="tag">&lt;script&gt;</span><span class="pln">
  </span><span class="com">// تأتي المزيد من التفاصيل مع الحدث إلى المعالج</span><span class="pln">
  elem</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"hello"</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    alert</span><span class="pun">(</span><span class="pln">event</span><span class="pun">.</span><span class="pln">detail</span><span class="pun">.</span><span class="pln">name</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">});</span><span class="pln">

  elem</span><span class="pun">.</span><span class="pln">dispatchEvent</span><span class="pun">(</span><span class="kwd">new</span><span class="pln"> </span><span class="typ">CustomEvent</span><span class="pun">(</span><span class="str">"hello"</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    detail</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"John"</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">}));</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" data-ss1613985682="1" frameborder="no" height="198" loading="lazy" scrolling="no" src="https://codepen.io/Hsoub/embed/preview/mdOBMKr?height=198&amp;theme-id=light&amp;default-tab=result" style="width: 100%;" title="JS-p2-dispatch-events -ex3">See the Pen JS-p2-dispatch-events -ex3 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	يمكن أن تحوي هذه الخاصيّة أي معطيات. في الحقيقة، من الممكن أن نعمل بدونها، لأننا نستطيع أن نسند أيّ خاصيّة إلى كائن <code>new Event</code> عاديّ بعد إنشائه. لكن <code>CustomEvent</code> تزوّده بحقل <code>detail</code> الخاص لتفادي التعارض مع خاصيّات الحدث الأخرى.
</p>

<p>
	إلى جانب ذلك، يبيّن صنف الحدث "أيّ نوع حدث" هو، وإذا كان الحدث مخصّصا، فينبغي استخدام <code>CustomEvent</code> لنكون فقط واضحين بخصوصه.
</p>

<h2>
	()event.preventDefault
</h2>

<p>
	لدى العديد من أحداث المتصفّح "أفعال افتراضيّة"، كالانتقال إلى رابط، بداية تحديد، وما إلى ذلك.
</p>

<p>
	أمّا الأحداث المخصّصة الجديدة، فليس لديها بالطبع أيّة أفعال افتراضيًّة، لكن قد تكون للشيفرة التي ترسل مثل هذه الأحداث خُططًا خاصّة تقوم بها بعد افتعال الحدث.
</p>

<p>
	باستدعاء <code>event.preventDefault()‎</code> ، يمكن لمعالج الحدث أن يرسل إشارة بإنّ تلك الأفعال المخطّط لها يجب أن تُلغى.
</p>

<p>
	في تلك الحالة يعيد الاستدعاء <code>elem.dispatchEvent(event)‎</code> القيمة <code>false</code>. وتعلم الشيفرةُ التي أرسلت الحدث بأنّ عليها ألا تكمل.
</p>

<p>
	لنرى مثالًا تطبيقيّا لذلك -- أرنب متخفّي (قد يكون قائمة أيضا منغلقة أو أيّ شيئ آخر).
</p>

<p>
	يمكن أن ترى في الأسفل الأرنب <code>rabbit#</code> وعليه الدالة <code>hide()‎</code> التي ترسل الحدث <code>"hide"</code>، لتعلم جميع الأطراف المعنيّة بأنّ الأرنب سيختفي.
</p>

<p>
	يمكن لأي معالج أن يستمع لذلك الحدث بواسطة <code>rabbit.addEventListener('hide',...)‎</code> ، وإن تتطلّب الأمر، يمكنه إلغاء الفعل باستخدام <code>event.preventDefault()‎</code>. فعندها لن يختفي الأرنب:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_2146_19" style="">
<span class="tag">&lt;pre</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"rabbit"</span><span class="tag">&gt;</span><span class="pln">
  |\   /|
   \|_|/
   /. .\
  =\_Y_/=
   {&gt;o&lt;}
</span><span class="tag">&lt;/pre&gt;</span><span class="pln">
</span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">onclick</span><span class="pun">=</span><span class="atv">"</span><span class="pln">hide</span><span class="pun">()</span><span class="atv">"</span><span class="tag">&gt;</span><span class="pln">Hide()</span><span class="tag">&lt;/button&gt;</span><span class="pln">

</span><span class="tag">&lt;script&gt;</span><span class="pln">
  </span><span class="kwd">function</span><span class="pln"> hide</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let event </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">CustomEvent</span><span class="pun">(</span><span class="str">"hide"</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      cancelable</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln"> </span><span class="com">// preventDefault بدون تلك الراية لا يعمل</span><span class="pln">
    </span><span class="pun">});</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(!</span><span class="pln">rabbit</span><span class="pun">.</span><span class="pln">dispatchEvent</span><span class="pun">(</span><span class="pln">event</span><span class="pun">))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      alert</span><span class="pun">(</span><span class="str">'The action was prevented by a handler'</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      rabbit</span><span class="pun">.</span><span class="pln">hidden </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  rabbit</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">'hide'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">confirm</span><span class="pun">(</span><span class="str">"Call preventDefault?"</span><span class="pun">))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      event</span><span class="pun">.</span><span class="pln">preventDefault</span><span class="pun">();</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">});</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" data-ss1613985682="1" frameborder="no" height="264" loading="lazy" scrolling="no" src="https://codepen.io/Hsoub/embed/abBLyKg?height=264&amp;theme-id=light&amp;default-tab=result" style="width: 100%;" title="JS-p2-dispatch-events -ex4">See the Pen JS-p2-dispatch-events -ex4 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	يرجى التنبه هنا: يجب أن يكون للحدث الراية <code>cancelable: true</code>، وإلّا فسيُهمل <code>event.preventDefault()‎</code> .
</p>

<h2>
	تعمل الأحداث التي داخل أحداث أخرى بشكل متزامن
</h2>

<p>
	تُعالَج الأحداث عادةً على شكل طابور. بعبارة أخرى، إذا كان المتصفّح يقوم بمعالجة <code>onclick</code> ووقع حدث جديد، كتحريك الفأرة مثلًا، فإن معالجته تُصفّ في طابور الانتظار، وتُستدعى المعالجات المتعلّقة بـ <code>mousemove</code> بعد الانتهاء من معالجة <code>onclick</code>.
</p>

<p>
	الاستثناء الجدير بالانتباه هنا هو عندما ينشأ حدث من داخل حدث آخر، بواسطة <code>dispatchEvent</code> مثلا. تُعالج تلك الأحداث فورًا: تُستدعى معالجات الحدث الجديد ثم تستمر معالجة الحدث الحالية.
</p>

<p>
	على سبيل المثال، في الشيفرة أدناه يُفتعل الحدث <code>menu-open</code> خلال الحدث <code>onclick</code>. ويُعالَج فورًا دون انتظار معالج <code>onclick</code> من الانتهاء:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_2146_21" style="">
<span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"menu"</span><span class="tag">&gt;</span><span class="pln">Menu (click me)</span><span class="tag">&lt;/button&gt;</span><span class="pln">

</span><span class="tag">&lt;script&gt;</span><span class="pln">
  menu</span><span class="pun">.</span><span class="pln">onclick </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    alert</span><span class="pun">(</span><span class="lit">1</span><span class="pun">);</span><span class="pln">

    menu</span><span class="pun">.</span><span class="pln">dispatchEvent</span><span class="pun">(</span><span class="kwd">new</span><span class="pln"> </span><span class="typ">CustomEvent</span><span class="pun">(</span><span class="str">"menu-open"</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      bubbles</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
    </span><span class="pun">}));</span><span class="pln">

    alert</span><span class="pun">(</span><span class="lit">2</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">};</span><span class="pln">

  </span><span class="com">//  يفتعل بين 1 و 2</span><span class="pln">
  document</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">'menu-open'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> alert</span><span class="pun">(</span><span class="str">'nested'</span><span class="pun">));</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" data-ss1613985682="1" frameborder="no" height="164" loading="lazy" scrolling="no" src="https://codepen.io/Hsoub/embed/mdOBMjO?height=164&amp;theme-id=light&amp;default-tab=result" style="width: 100%;" title="JS-p2-dispatch-events -ex5">See the Pen JS-p2-dispatch-events -ex5 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	يكون ترتيب المخرجات كما يلي: 1 -› الحدث الداخلي -› 2.
</p>

<p>
	يُرجى التنبّه إلى أنّ الحدث الداخليّ <code>menu-open</code> قد تم ألتقاطه على مستوى <code>document</code>. يتمّ انتشار الحدث الداخلي ومعالجته قبل عودة المعالجة إلى الشيفرة الخارجية (<code>onclick</code>).
</p>

<p>
	لا يخصّ هذا فقط <code>dispatchEvent</code>، بل هناك حالات أخرى. إذا استدعى معالجٌ توابعَ تفتعل أحداثًا أخرى، فإنّها تُعالج تزامنيًّا أيضًا، بشكلٍ متداخل.
</p>

<p>
	لكن لنفترض أنّنا لا نريد ذلك. نريد أن تتمّ معالجة <code>onclick</code> أوّلًا، باستقلالٍ عن <code>menu-open</code> أو غيره من اﻷحداث المتداخلة.
</p>

<p>
	يمكننا عندها إمّا أن نضع <code>dispatchEvent</code> (أو نداءَ افتعال أحداثٍ آخر) في آخر <code>onclick</code>، أو ربّما أفضل، أن نلفّه بـ <code>setTimeout</code> منعدمة التأخير:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_2146_23" style="">
<span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"menu"</span><span class="tag">&gt;</span><span class="pln">Menu (click me)</span><span class="tag">&lt;/button&gt;</span><span class="pln">

</span><span class="tag">&lt;script&gt;</span><span class="pln">
  menu</span><span class="pun">.</span><span class="pln">onclick </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    alert</span><span class="pun">(</span><span class="lit">1</span><span class="pun">);</span><span class="pln">

    setTimeout</span><span class="pun">(()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> menu</span><span class="pun">.</span><span class="pln">dispatchEvent</span><span class="pun">(</span><span class="kwd">new</span><span class="pln"> </span><span class="typ">CustomEvent</span><span class="pun">(</span><span class="str">"menu-open"</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      bubbles</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
    </span><span class="pun">})));</span><span class="pln">

    alert</span><span class="pun">(</span><span class="lit">2</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">};</span><span class="pln">

  document</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">'menu-open'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> alert</span><span class="pun">(</span><span class="str">'nested'</span><span class="pun">));</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" data-ss1613985682="1" frameborder="no" height="161" loading="lazy" scrolling="no" src="https://codepen.io/Hsoub/embed/NWbavBX?height=161&amp;theme-id=light&amp;default-tab=result" style="width: 100%;" title="JS-p2-dispatch-events -ex6">See the Pen JS-p2-dispatch-events -ex6 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	تعمل الآن <code>dispatchEvent</code> لا تزامنيًّا بعد الانتهاء من تنفيذ الشيفرة الحاليّة، بما في ذلك <code>menu.onclick</code>، وتصير بذلك معالجات الأحداث منفصلة تمامًا. ويصير ترتيب المخرجات كالتالي: 1 -&gt; 2 -&gt; الحدث الداخلي.
</p>

<h2>
	الملخص
</h2>

<p>
	لتوليد حدثٍ من خلال الشيفرة، نحتاج أوّلًا أن ننشئ كائن حدث.
</p>

<p>
	يقبل الباني العام <code>Event(name, options)‎</code> اسمًا للحدث والكائن <code>options</code> مع الخاصّيّتين:
</p>

<ul>
<li>
		<code>bubbles: true</code> إذا كان يجب أن ينتشر الحدث نحو اﻷعلى.
	</li>
	<li>
		<code>cancelable: true</code> إذا كان يجب أن يعمل <code>event.preventDefault()‎</code>.
	</li>
</ul>
<p>
	يقبل بانو الأحداث اﻷصليّة الآخرون مثل <code>MouseEvent</code> و <code>KeyboardEvent</code> و ما إلى ذلك، خاصّيّات مختصّة بنوع الحدث ذلك. على سبيل المثال، <code>clientX</code> لأحداث المؤشر.
</p>

<p>
	ينبغي أن نستخدم الباني <code>CustomEvent</code> للأحداث المخصّصة. فلديه خيار إضافيّ اسمه <code>detail</code>، يمكن أن نسند إليه المعطيات المختصّة بالحدث. وبذلك يمكن لجميع المعالجات الوصول إليها بواسطة <code>event.detail</code>.
</p>

<p>
	بالرغم من الإمكانيّة التقنيّة لتوليد أحداث المتصفّح مثل <code>click</code> أو <code>keydown</code>، فينبغي استخدامها بحذرٍ شديد.
</p>

<p>
	لا ينبغي أن نعمد إلى توليد أحداث المتصفّح، إذ يعدّ ذلك طريقة مبتذلة لتشغيل المعالجات. وهي هندسة سيّئة في أغلب اﻷحيان.
</p>

<p>
	يمكن أن تُولّد اﻷحداث اﻷصليّة:
</p>

<ul>
<li>
		كطريقة مبتذلة لجعل مكتبات الطرف الثالث تعمل كما يجب، إذا لم تكن توفّر وسائل أخرى للتفاعل معها.
	</li>
	<li>
		عند إجراء الاختبارات الآليّة، مثل "النقر على الزرّ" من خلال السكربت لمعرفة ما إذا كانت الواجهة تستجيب بشكل صحيح.
	</li>
</ul>
<p>
	تُولَّد الأحداث المخصّصة بأسمائنا الخاصّة لأغراض هندسيّة في الغالب، للإشارة إلى ما يحصل داخل القوائم و الدوّارات وما إلى ذلك.
</p>

<p>
	ترجمة -وبتصرف- للمقال <a data-ss1613985682="1" href="https://javascript.info/dispatch-events" rel="external nofollow">Dispatching custom events</a> من سلسلة <a data-ss1613985682="1" href="https://javascript.info/ui" rel="external nofollow">Browser: Document, Events, Interfaces</a> لصاحبها Ilya Kantor
</p>
]]></description><guid isPermaLink="false">1144</guid><pubDate>Sat, 06 Mar 2021 13:03:00 +0000</pubDate></item><item><title>&#x623;&#x641;&#x639;&#x627;&#x644; &#x627;&#x644;&#x645;&#x62A;&#x635;&#x641;&#x62D; &#x627;&#x644;&#x627;&#x641;&#x62A;&#x631;&#x627;&#x636;&#x64A;&#x629; &#x644;&#x644;&#x623;&#x62D;&#x62F;&#x627;&#x62B; &#x648;&#x636;&#x628;&#x637;&#x647;&#x627; &#x639;&#x628;&#x631; &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A;</title><link>https://academy.hsoub.com/programming/javascript/%D8%A3%D9%81%D8%B9%D8%A7%D9%84-%D8%A7%D9%84%D9%85%D8%AA%D8%B5%D9%81%D8%AD-%D8%A7%D9%84%D8%A7%D9%81%D8%AA%D8%B1%D8%A7%D8%B6%D9%8A%D8%A9-%D9%84%D9%84%D8%A3%D8%AD%D8%AF%D8%A7%D8%AB-%D9%88%D8%B6%D8%A8%D8%B7%D9%87%D8%A7-%D8%B9%D8%A8%D8%B1-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r1143/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_02/4.png.c25fb950de5129cff5f4e27e40a70b7d.png" /></p>

<p>
	تتسبّب الكثير من الأحداث في قيام المتصفّح تلقائيّا بأفعالٍ معيّنة. على سبيل المثال:
</p>

<ul>
<li>
		يتسبّب النقر على رابط في الانتقال إلى عنوانه.
	</li>
	<li>
		يتسبّب النقر على زرّ الإرسال في نموذج في إرساله إلى الخادم.
	</li>
	<li>
		يتسبّب الضغط على زرّ الفأرة فوق نصّ وتحريكها في تحديد ذلك النصّ.
	</li>
</ul>
<p>
	في حال معالجة الحدث في جافاسكربت، قد لا نريد حصول فعل المتصفّح المقابل له، ونريد تطبيق سلوكٍ آخر في مكانه.
</p>

<h2>
	منع أفعال المتصفح
</h2>

<p>
	هناك طريقتان لإخبار المتصفّح بأنّنا لا نريده أن يعمل:
</p>

<ul>
<li>
		الطريقة الرئيسيّة هي استخدام الكائن <code>event</code>، الذي لديه التابع <code>event.preventDefault()‎</code>.
	</li>
	<li>
		إذا أٌسند المعالج باستخدام <code>on&lt;event&gt;‎</code> (لا باستخدام <code>addEventListener</code>) ، فإنّ إعادة القيمة <code>false</code> تؤدي نفس الغرض أيضا.
	</li>
</ul>
<p>
	في شيفرة HTML أسفله، لا يتسبّب النقر على الرابط في الانتقال إلى عنوانه، لا يفعل المتصفّح أيّ شيء.
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_2220_7" style="">
<span class="tag">&lt;a</span><span class="pln"> </span><span class="atn">href</span><span class="pun">=</span><span class="atv">"/"</span><span class="pln"> </span><span class="atn">onclick</span><span class="pun">=</span><span class="atv">"</span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">false</span><span class="atv">"</span><span class="tag">&gt;</span><span class="pln">Click here</span><span class="tag">&lt;/a&gt;</span><span class="pln">
or
</span><span class="tag">&lt;a</span><span class="pln"> </span><span class="atn">href</span><span class="pun">=</span><span class="atv">"/"</span><span class="pln"> </span><span class="atn">onclick</span><span class="pun">=</span><span class="atv">"</span><span class="pln">event</span><span class="pun">.</span><span class="pln">preventDefault</span><span class="pun">()</span><span class="atv">"</span><span class="tag">&gt;</span><span class="pln">here</span><span class="tag">&lt;/a&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" data-ss1613984917="1" data-ss1613985164="1" frameborder="no" height="265" loading="lazy" scrolling="no" src="https://codepen.io/Hsoub/embed/BaQwdRp?height=265&amp;theme-id=light&amp;default-tab=result" style="width: 100%;" title="JS-p2-browser-default-actions -ex1">See the Pen JS-p2-browser-default-actions -ex1 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	في المثال التالي، سنستخدم هذه الطريقة لإنشاء قائمة تعمل بواسطة جافاسكربت.
</p>

<hr>
<p>
	<strong>تنبيه: إعادة <code>false</code> من المعالج هو استثناء</strong>
</p>

<p>
	تُهمل عادةً القيمة المُعادة من طرف المعالج. الاستثناء الوحيد هو <code>return false</code> من المعالج المسنَد باستخدام <code>on&lt;event&gt;‎</code>. في جميع الحالات الأخرى، تُهمل قيمة <code>return</code>. على وجه الخصوص، لا معنى لإعادة <code>true</code>.
</p>

<hr>
<h3>
	مثال: القائمة
</h3>

<p>
	لنفترض قائمة موقع كهذه:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_2220_9" style="">
<span class="tag">&lt;ul</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"menu"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"menu"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;li&gt;&lt;a</span><span class="pln"> </span><span class="atn">href</span><span class="pun">=</span><span class="atv">"/html"</span><span class="tag">&gt;</span><span class="pln">HTML</span><span class="tag">&lt;/a&gt;&lt;/li&gt;</span><span class="pln">
  </span><span class="tag">&lt;li&gt;&lt;a</span><span class="pln"> </span><span class="atn">href</span><span class="pun">=</span><span class="atv">"/javascript"</span><span class="tag">&gt;</span><span class="pln">JavaScript</span><span class="tag">&lt;/a&gt;&lt;/li&gt;</span><span class="pln">
  </span><span class="tag">&lt;li&gt;&lt;a</span><span class="pln"> </span><span class="atn">href</span><span class="pun">=</span><span class="atv">"/css"</span><span class="tag">&gt;</span><span class="pln">CSS</span><span class="tag">&lt;/a&gt;&lt;/li&gt;</span><span class="pln">
</span><span class="tag">&lt;/ul&gt;</span></pre>

<p>
	بإضافة بعض تنسيقات CSS ستبدو كما <a data-ss1613984917="1" data-ss1613985164="1" href="https://en.js.cx/article/default-browser-action/menu/" rel="external nofollow">هنا</a>.
</p>

<p>
	تُنشأ عناصر القائمة على شكل روابط HTML أي <code>&lt;a&gt;</code>، لا على شكل أزرار <code>&lt;button&gt;</code>. هناك عدّة أسباب لفعل ذلك، فمثلًا:
</p>

<ul>
<li>
		يحبّذ كثيرٌ من الناس استخدام "النقر باليمين" ثم "افتح في نافذة جديدة". لو استخدمنا <code>&lt;button&gt;</code> أو <code>&lt;span&gt;</code> فلن يعمل ذلك.
	</li>
	<li>
		تتتبّع محرّكات البحث الروابط <code>&lt;a href="..."‎&gt;</code> عند الفهرسة.
	</li>
</ul>
<p>
	بالتالي سنستخدم <code>&lt;a&gt;</code> عند إضافة الروابط في HTML. لكنّّنا نودّ عادةً معالجة النقرات على الروابط بواسطة جافاسكربت. فيجب إذًا أن نمنع فعل المتصفّح الافتراضي.كما هو مبيّن هنا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2220_11" style="">
<span class="pln">menu</span><span class="pun">.</span><span class="pln">onclick </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">event</span><span class="pun">.</span><span class="pln">target</span><span class="pun">.</span><span class="pln">nodeName </span><span class="pun">!=</span><span class="pln"> </span><span class="str">'A'</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">return</span><span class="pun">;</span><span class="pln">

  let href </span><span class="pun">=</span><span class="pln"> event</span><span class="pun">.</span><span class="pln">target</span><span class="pun">.</span><span class="pln">getAttribute</span><span class="pun">(</span><span class="str">'href'</span><span class="pun">);</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln"> href </span><span class="pun">);</span><span class="pln"> </span><span class="com">// قد يُحمّل من الخادم أو تُولّد واجهة المستخدم إلى غير ذلك ...</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln"> </span><span class="com">//  (لا تذهب إلى العنوان) ‎ امنع فعل المتصفّح</span><span class="pln">
</span><span class="pun">};</span></pre>

<p>
	إذا حذفنا <code>return false</code>، فسيقوم المتصفّح بعد تنفيذ الشيفرة "بفعله الافتراضي" -- الانتقال إلى العنوان الذي في <code>href</code>. ولا نحتاج ذلك هنا، إذ نعالج النقرات بأنفسنا.
</p>

<p>
	بالمناسبة، يساعد استخدام تفويض الحدث هنا في جعل القائمة مرنة. يمكننا إضافة قوائم متداخلة وتنسيقها باستخدام CSS حتى "تنزلق إلى الأسفل".
</p>

<hr>
<p>
	<strong>ملاحظة: الأحداث المتتابعة</strong>
</p>

<p>
	تجري بعض الأحداث الواحد تلو الآخر. فإذا منعنا الحدث الأوّل، لن يكون الثاني.
</p>

<p>
	على سبيل المثال، يؤدّي وقوع الحدث <code>mousedown</code> على حقل <code>&lt;input&gt;</code> إلى التركيز عليه، ووقوع حدث <code>focus</code>. فإذا منعنا الحدث <code>mousedown</code>، لن يكون هناك تركيز.
</p>

<p>
	جرّب النقر على <code>&lt;input&gt;</code> الأوّل من هنا -- يقع الحدث <code>focus</code>. لكن لو نقرت على الثاني، لن يكون هناك تركيز.
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_2220_13" style="">
<span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">value</span><span class="pun">=</span><span class="atv">"Focus works"</span><span class="pln"> </span><span class="atn">onfocus</span><span class="pun">=</span><span class="atv">"</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">value</span><span class="pun">=</span><span class="str">''</span><span class="atv">"</span><span class="tag">&gt;</span><span class="pln">
</span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">onmousedown</span><span class="pun">=</span><span class="atv">"</span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">false</span><span class="atv">"</span><span class="pln"> </span><span class="atn">onfocus</span><span class="pun">=</span><span class="atv">"</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">value</span><span class="pun">=</span><span class="str">''</span><span class="atv">"</span><span class="pln"> </span><span class="atn">value</span><span class="pun">=</span><span class="atv">"Click me"</span><span class="tag">&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" data-ss1613984917="1" data-ss1613985164="1" frameborder="no" height="265" loading="lazy" scrolling="no" src="https://codepen.io/Hsoub/embed/rNWGzwq?height=265&amp;theme-id=light&amp;default-tab=result" style="width: 100%;" title="JS-p2-browser-default-actions -ex2">See the Pen JS-p2-browser-default-actions -ex2 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	هذا لأنّ فعل المتصفّح قد أُلغي عند <code>mousedown</code>. يبقى وقوع التركيز ممكنا إذا استخدمنا طريقة أخرى للوصول إلى المُدخَل. على سبيل المثال، بواسطة المفتاح <code>Tab</code> للانتقال من المُدخَل الأوّل إلى الثاني. لكن ليس باستخدام النقر بالفأرة.
</p>

<hr>
<h3>
	خيار المعالج "السلبي (passive)"
</h3>

<p>
	يشير الخيار الاختياري <code>passive: true</code> لـ <code>addEventListener</code> إلى المتصفّح بأنّ المعالج لن يستدعي <code>preventDefault()‎</code>. لكن لماذا قد يُحتاج لذلك؟
</p>

<p>
	تتسبّب بعض الأحداث مثل <code>touchmove</code> على الأجهزة اللمسية (عندما يحرّك المستخدم اصبعه على الشاشة) في تمرير (scroll) الصفحة افتراضيًّا، لكن قد يُمنع ذلك التمرير باستخدام <code>preventDefault()‎</code> في المعالج.
</p>

<p>
	فإذا تحسّس المتصفّح مثل هذه الأحداث، عليه أوّلًا دراسة جميع المعالجات للتحقّق من عدم استدعاء <code>preventDefault</code> في أيٍّ منها، ليتمكّن عندها من الشروع في التمرير. قد يُسبّب هذا تأخيرات و "ارتجاجات" غير ضروريّة في واجهة المستخدم.
</p>

<p>
	يُعلِم الخيارُ <code>passive: true</code> المتصفّحَ بأنّ المعالج لن يلغي التمرير. فيقوم المتصفّح بالتمرير مباشرة مقدّمًا بذلك تجربة سلسلة للغاية.
</p>

<p>
	تكون قيمة <code>passive</code> في بعض المتصفّحات (Firefox, Chrome) هي <code>true</code> افتراضيًّا للأحداث <code>touchstart</code> و <code>touchmove</code>.
</p>

<hr>
<h2>
	vent.defaultPrevented
</h2>

<p>
	تكون قيمة الخاصيّة <code>event.defaultPrevented</code> هي <code>true</code> إذا مُنع الفعل الافتراضي، وإلّا فهي <code>false</code>.
</p>

<p>
	هناك حالة استخدامٍ لذلك مثيرة للاهتمام. تذكر أنّنا تحدّثنا في مقال <a data-ss1613984917="1" data-ss1613985164="1" href="https://academy.hsoub.com/programming/javascript/%D9%81%D9%87%D9%85-%D8%B9%D9%85%D9%84%D9%8A%D8%A9-%D8%A7%D9%86%D8%AA%D8%B4%D8%A7%D8%B1-%D8%A7%D9%84%D8%A3%D8%AD%D8%AF%D8%A7%D8%AB-%D9%81%D9%8A-%D8%A7%D9%84%D9%85%D8%AA%D8%B5%D9%81%D8%AD-%D9%88%D8%A7%D9%84%D8%AA%D8%AD%D9%83%D9%85-%D9%81%D9%8A%D9%87%D8%A7-%D8%B9%D8%A8%D8%B1-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r1141/" rel="">انتشار الأحداث</a> عن <code>event.stopPropagation()‎</code>، وكيف أنّ إيقاف انتشار الأحداث نحو الأعلى أمرٌ سيّء. يمكن أحيانًا استخدام <code>event.defaultPrevented</code> بدل ذلك، لإعلام المعالجات الأخرى بأنّ الحدث قد تمّت معالجته. لنرى مثالًا عمليّا لذلك.
</p>

<p>
	يُظهر المتصفّح افتراضيًّا عند الحدث <code>contextmenu</code> (النقر بزرّ الفأرة الأيمن) قائمة منبثقة تضمّ خيارات اعتياديّة. يمكننا منع ذلك، وإظهار قائمتنا نحن بدلها، هكذا:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_2220_16" style="">
<span class="tag">&lt;button&gt;</span><span class="pln">Right-click shows browser context menu</span><span class="tag">&lt;/button&gt;</span><span class="pln">

</span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">oncontextmenu</span><span class="pun">=</span><span class="atv">"</span><span class="pln">alert</span><span class="pun">(</span><span class="str">'Draw our menu'</span><span class="pun">);</span><span class="pln"> </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">false</span><span class="atv">"</span><span class="tag">&gt;</span><span class="pln">
  Right-click shows our context menu
</span><span class="tag">&lt;/button&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" data-ss1613984917="1" data-ss1613985164="1" frameborder="no" height="265" loading="lazy" scrolling="no" src="https://codepen.io/Hsoub/embed/WNoZEjE?height=265&amp;theme-id=light&amp;default-tab=result" style="width: 100%;" title="JS-p2-browser-default-actions -ex3">See the Pen JS-p2-browser-default-actions -ex3 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	بالإضافة إلى تلك القائمة المنبثقة، نودّ الآن إنشاء قائمة منبثقة تعمل على مستوى المستند.
</p>

<p>
	عند النقر باليمين، يجب أن تظهر أقرب قائمة.
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_2220_18" style="">
<span class="tag">&lt;p&gt;</span><span class="pln">Right-click here for the document context menu</span><span class="tag">&lt;/p&gt;</span><span class="pln">
</span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"elem"</span><span class="tag">&gt;</span><span class="pln">Right-click here for the button context menu</span><span class="tag">&lt;/button&gt;</span><span class="pln">

</span><span class="tag">&lt;script&gt;</span><span class="pln">
  elem</span><span class="pun">.</span><span class="pln">oncontextmenu </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    event</span><span class="pun">.</span><span class="pln">preventDefault</span><span class="pun">();</span><span class="pln">
    alert</span><span class="pun">(</span><span class="str">"Button context menu"</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">};</span><span class="pln">

  document</span><span class="pun">.</span><span class="pln">oncontextmenu </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    event</span><span class="pun">.</span><span class="pln">preventDefault</span><span class="pun">();</span><span class="pln">
    alert</span><span class="pun">(</span><span class="str">"Document context menu"</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">};</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" data-ss1613984917="1" data-ss1613985164="1" frameborder="no" height="265" loading="lazy" scrolling="no" src="https://codepen.io/Hsoub/embed/poNWrPa?height=265&amp;theme-id=light&amp;default-tab=result" style="width: 100%;" title="JS-p2-browser-default-actions -ex4">See the Pen JS-p2-browser-default-actions -ex4 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	المشكلة أنّه عندما ننقر على <code>elem</code>، فإننا نحصل على قائمتين: التي على مستوى الزرّ و (بانتشار الحدث نحو الأعلى) التي على مستوى المستند.
</p>

<p>
	كيف يمكن إصلاح ذلك؟ يعتمد أحد الحلول على هذه الفكرة: "عند معالجة حدث النقر باليمين من طرف المعالج المسند إلى الزرّ، لنقم بإيقاف انتشاره نحو الأعلى باستخدام <code>event.stopPropagation()‎</code>:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_2220_20" style="">
<span class="tag">&lt;p&gt;</span><span class="pln">Right-click for the document menu</span><span class="tag">&lt;/p&gt;</span><span class="pln">
</span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"elem"</span><span class="tag">&gt;</span><span class="pln">Right-click for the button menu (fixed with event.stopPropagation)</span><span class="tag">&lt;/button&gt;</span><span class="pln">

</span><span class="tag">&lt;script&gt;</span><span class="pln">
  elem</span><span class="pun">.</span><span class="pln">oncontextmenu </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    event</span><span class="pun">.</span><span class="pln">preventDefault</span><span class="pun">();</span><span class="pln">
    event</span><span class="pun">.</span><span class="pln">stopPropagation</span><span class="pun">();</span><span class="pln">
    alert</span><span class="pun">(</span><span class="str">"Button context menu"</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">};</span><span class="pln">

  document</span><span class="pun">.</span><span class="pln">oncontextmenu </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    event</span><span class="pun">.</span><span class="pln">preventDefault</span><span class="pun">();</span><span class="pln">
    alert</span><span class="pun">(</span><span class="str">"Document context menu"</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">};</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" data-ss1613984917="1" data-ss1613985164="1" frameborder="no" height="265" loading="lazy" scrolling="no" src="https://codepen.io/Hsoub/embed/yLVzobK?height=265&amp;theme-id=light&amp;default-tab=result" style="width: 100%;" title="JS-p2-browser-default-actions -ex5">See the Pen JS-p2-browser-default-actions -ex5 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	تعمل الآن القائمة التي على مستوى الزرّ كما ينبغي. لكن الثمن باهظ. سنحرم جميع الشيفرات الخارجية من الوصول إلى المعلومات الخاصة بالنقرات اليمنى إلى الأبد، بما في ذلك العدّادات التي تحصي وما إلى ذلك. ليس هذا من الحكمة على الإطلاق.
</p>

<p>
	الحلّ البديل هو التحقّق في معالج <code>document</code> ممّا إذا كان الفعل الافتراضي قد مُنع. وإذا كان كذلك، فإنّ الحدث قد عولج، ولا حاجة لكي نستجيب له.
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_2220_22" style="">
<span class="tag">&lt;p&gt;</span><span class="pln">Right-click for the document menu (added a check for event.defaultPrevented)</span><span class="tag">&lt;/p&gt;</span><span class="pln">
</span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"elem"</span><span class="tag">&gt;</span><span class="pln">Right-click for the button menu</span><span class="tag">&lt;/button&gt;</span><span class="pln">

</span><span class="tag">&lt;script&gt;</span><span class="pln">
  elem</span><span class="pun">.</span><span class="pln">oncontextmenu </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    event</span><span class="pun">.</span><span class="pln">preventDefault</span><span class="pun">();</span><span class="pln">
    alert</span><span class="pun">(</span><span class="str">"Button context menu"</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">};</span><span class="pln">

  document</span><span class="pun">.</span><span class="pln">oncontextmenu </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">event</span><span class="pun">.</span><span class="pln">defaultPrevented</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">return</span><span class="pun">;</span><span class="pln">

    event</span><span class="pun">.</span><span class="pln">preventDefault</span><span class="pun">();</span><span class="pln">
    alert</span><span class="pun">(</span><span class="str">"Document context menu"</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">};</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" data-ss1613984917="1" data-ss1613985164="1" frameborder="no" height="265" loading="lazy" scrolling="no" src="https://codepen.io/Hsoub/embed/eYBGEWL?height=265&amp;theme-id=light&amp;default-tab=result" style="width: 100%;" title="JS-p2-browser-default-actions -ex6">See the Pen JS-p2-browser-default-actions -ex6 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	كل شيء يعمل الآن بشكل صحيح. إذا كانت لدينا عناصر متداخلة، ولكلٍّ منها قائمته المنبثقة، فإنّ ذلك سيعمل أيضا. احرص فقط على التحقّق من وجود <code>event.defaultPrevented</code> في كلّ معالجات <code>contextmenu</code>.
</p>

<hr>
<p>
	<strong>ملاحظة: ()event.stopPropagation و ()event.preventDefault</strong>
</p>

<p>
	كما يمكننا رؤية ذلك بوضوح، <code>event.stopPropagation()‎</code> و <code>event.preventDefault()‎</code> (أو ما يُعرف أيضا بـ <code>return false</code>) هما شيئان مختلفان. لا علاقة لهما ببعضهما البعض.
</p>

<hr>
<hr>
<p>
	<strong>ملاحظة: هندسة القوائم المنبثقة المتداخلة</strong>
</p>

<p>
	هناك أيضا طرق بديلة لتطبيق قوائم منبثقة متداخلة. إحداها هو أخذ كائن عامّ وحيد له المعالج <code>document.oncontextmenu</code>، وله كذلك توابع تمكّننا من تخزين معالجات أخرى داخله.
</p>

<p>
	سيعمل الكائن على التقاط كلّ النقرات اليمنى، ثم ينظر في المعالجات المخزَّنة ويُشغّل المعالج المناسب.
</p>

<p>
	لكن عندها، بجب على كلّ قطعة شيفرة تريد قائمة منبثقة أن تكون على علم بذلك المعالج، وتستعين به بدل معالج <code>contextmenu</code> خاصّ بها.
</p>

<hr>
<h2>
	الملخص
</h2>

<p>
	هناك عدة أفعال افتراضيًّة للمتصفّح:
</p>

<ul>
<li>
		<code>mousedown</code> -- يبدأ عمليّة التحديد (تُحرٌك الفأرة للتحديد).
	</li>
	<li>
		<code>click</code> على <code>&lt;input type="checkbox"‎&gt;</code> -- إضافة أو إزالة التأشير على الخانة <code>input</code>.
	</li>
	<li>
		<code>submit</code> -- يتسبّب النقر على <code>&lt;input type="submit"‎&gt;</code> أو الضغط على مفتاح <code>Enter</code> داخل حقل في نموذج بوقوع هذا الحدث، ويرسل المتصفّحُ النموذجَ بعد ذلك.
	</li>
	<li>
		<code>keydown</code> -- قد يتسبّب الضغط على مفتاحٍ في إضافة حرف داخل حقل، أو إلى فعل آخر.
	</li>
	<li>
		<code>contextmenu</code> -- يقع الحدث عند النقر باليمين، ويكون الفعل هو إظهار قائمة المتصفّح المنبثقة.
	</li>
	<li>
		… و يوجد هناك المزيد …
	</li>
</ul>
<p>
	يُمكن منع جميع الأفعال الافتراضية إذا أردنا معالجة الحدث حصريّا من خلال جافاسكربت.
</p>

<p>
	لمنع الفعل الافتراضيّ، استخدم إمّا <code>event.preventDefault()‎</code> أو <code>return false</code>. لا تعمل الطريقة الثانية إلّا مع المعالجات المسندة بواسطة <code>on&lt;event&gt;‎</code>.
</p>

<p>
	يُعلِم الخيارُ <code>passive: true</code> المتصفّحَ بأنّ الفعل الافتراضيّ لن يُمنع. هذا مفيد لبعض أحداث الأجهزة المحمولة، مثل <code>touchstart</code> و <code>touchmove</code>، لإعلام المتصفّح بأنّ ليس عليه انتظار الانتهاء من تشغيل جميع المعالجات قبل التمرير.
</p>

<p>
	إذا تمّ منع الفعل الافتراضيّ، فإنّ قيمة <code>event.defaultPrevented</code> تصير <code>true</code>، وإلّا فهي <code>false</code>.
</p>

<hr>
<p>
	<strong>تنبيه: حافظ على الدلاليّة، لا تفرط</strong>
</p>

<p>
	فنيّا، بمنع الأفعال الافتراضية واستخدام جافاسكربت يمكننا تخصيص سلوك أيّ عنصر. على سبيل المثال، يمكننا جعل رابط <code>&lt;a&gt;</code> يعمل مثل زرّ، وجعل زرّ <code>&lt;button&gt;</code> يتصرّف مثل رابط (ينقل إلى عنوان آخر ونحوه).
</p>

<p>
	لكن يجب عمومًا المحافظة على على المعاني الدلاليّة لعناصر HTML. على سبيل المثال، يجب أن يعمل على الانتقال الرابط، وليس الزرّ.
</p>

<p>
	إلى جانب كون ذلك "مجرّد أمر جيّد"، يجعل هذا شيفرة HTML أفضل من ناحية إمكانية الوصول (accessibility).
</p>

<p>
	بالإضافة إلى ذلك، يُرجى التنبّه إلى أن المتصفّح يتيح لنا إمكانيّة فتح الروابط <code>&lt;a&gt;</code> في نافذة مستقلّة (عن طريق النقر عليها باليمين وغير ذلك). ويودّ الناس ذلك. لكن لو جعلنا مكانها زرّا يعمل كرابط بواسطة جافاسكربت بل وجعلناه أيضا يبدو كرابط بواسطة CSS، فإنّ المزايا المختصّة بـ <code>&lt;a&gt;</code> التي يتيحها المتصفّح لن تعمل.
</p>

<hr>
<h2>
	التمارين
</h2>

<h3>
	لماذا لا تعمل "return false"؟
</h3>

<p>
	الأهمية: 3
</p>

<p>
	لماذا لا تعمل <code>return false</code> إطلاقًا في هذه الشيفرة:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_2220_24" style="">
<span class="tag">&lt;script&gt;</span><span class="pln">
  </span><span class="kwd">function</span><span class="pln"> handler</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    alert</span><span class="pun">(</span><span class="pln"> </span><span class="str">"..."</span><span class="pln"> </span><span class="pun">);</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span><span class="pln">

</span><span class="tag">&lt;a</span><span class="pln"> </span><span class="atn">href</span><span class="pun">=</span><span class="atv">"https://w3.org"</span><span class="pln"> </span><span class="atn">onclick</span><span class="pun">=</span><span class="atv">"</span><span class="pln">handler</span><span class="pun">()</span><span class="atv">"</span><span class="tag">&gt;</span><span class="pln">the browser will go to w3.org</span><span class="tag">&lt;/a&gt;</span></pre>

<p>
	يتّبع المتصفّح العنوان عند النقر، لكنّنا لا نريد ذلك.
</p>

<p>
	كيف يمكن إصلاحه؟
</p>

<h3>
	الحل
</h3>

<p>
	عندما يقرأ المتصفّح الخاصيّة <code>on*</code> مثل <code>onclick</code>، فإنّه ينشئ معالجًا من محتواها.
</p>

<p>
	فمن أجل <code>onclick="handler()"‎</code> تصير الدالّة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2220_28" style="">
<span class="kwd">function</span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  handler</span><span class="pun">()</span><span class="pln"> </span><span class="com">// onclick محتوى</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	نستطيع الآن أن نرى أن القيمة المعادة من طرف <code>handler()‎</code> غير مستعملة ولا تؤثر في النتيجة.
</p>

<p>
	طريقة إصلاح ذلك بسيطة:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_2220_30" style="">
<span class="tag">&lt;script&gt;</span><span class="pln">
  </span><span class="kwd">function</span><span class="pln"> handler</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    alert</span><span class="pun">(</span><span class="str">"..."</span><span class="pun">);</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span><span class="pln">

</span><span class="tag">&lt;a</span><span class="pln"> </span><span class="atn">href</span><span class="pun">=</span><span class="atv">"https://w3.org"</span><span class="pln"> </span><span class="atn">onclick</span><span class="pun">=</span><span class="atv">"</span><span class="kwd">return</span><span class="pln"> handler</span><span class="pun">()</span><span class="atv">"</span><span class="tag">&gt;</span><span class="pln">w3.org</span><span class="tag">&lt;/a&gt;</span></pre>

<p>
	يمكننا أيضا استخدام <code>event.preventDefault()‎</code>، هكذا:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_2220_32" style="">
<span class="tag">&lt;script&gt;</span><span class="pln">
  </span><span class="kwd">function</span><span class="pln"> handler</span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    alert</span><span class="pun">(</span><span class="str">"..."</span><span class="pun">);</span><span class="pln">
    event</span><span class="pun">.</span><span class="pln">preventDefault</span><span class="pun">();</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span><span class="pln">

</span><span class="tag">&lt;a</span><span class="pln"> </span><span class="atn">href</span><span class="pun">=</span><span class="atv">"https://w3.org"</span><span class="pln"> </span><span class="atn">onclick</span><span class="pun">=</span><span class="atv">"</span><span class="pln">handler</span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="atv">"</span><span class="tag">&gt;</span><span class="pln">w3.org</span><span class="tag">&lt;/a&gt;</span></pre>

<h3>
	التقط الروابط داخل العنصر
</h3>

<p>
	الأهمية: 5
</p>

<p>
	اجعل جميع الروابط داخل العنصر الذي له <code>id="contents"‎</code> تسأل المستخدم أوّلا إن كان يودّ المغادرة حقّا. فإذا كان لا يرغب، لا تذهب إلى العنوان.
</p>

<p>
	كما هو مبيّن <a data-ss1613984917="1" data-ss1613985164="1" href="https://en.js.cx/task/catch-link-navigation/solution/" rel="external nofollow">هنا</a>.
</p>

<p>
	التفاصيل:
</p>

<ul>
<li>
		يمكن أن تُحمّل شيفرة HTML داخل العنصر يدويّا، أو يمكن أن تُولّد ديناميكيّا في أيّ وقت، فلا سبيل لإيجاد جميع الروابط وإسناد معالجات إليها. استخدم تفويض الأحداث.
	</li>
	<li>
		قد يكون داخل المحتوى وسوم متداخلة. وداخل الروابط أيضا، مثل <code>&lt;a href=".."&gt;&lt;i&gt;...&lt;/i&gt;&lt;/a&gt;</code>.
	</li>
</ul>
<p>
	<a data-ss1613984917="1" data-ss1613985164="1" href="https://plnkr.co/edit/2q3DhC51iVEYU3Ht?p=preview" rel="external nofollow">افتح البيئة التجريبية لإنجاز التمرين</a>
</p>

<h3>
	الحل
</h3>

<p>
	هذا استعمال جيّد لنمط تفويض الأحداث.
</p>

<p>
	في الحالات الواقعية، بدل سؤال المستخدم، يمكننا إرسال طلب "التسجيل" (logging" request") إلى الخادم الذي يحفظ مكان مغادرة المستخدم. أو يمكننا تحميل المحتوى وعرضه في نفس الصفحة (إذا كان ذلك مسموحًا).
</p>

<p>
	كلّ ما نحتاجه هو التقاط الأحداث <code>contents.onclick</code> واستخدام <code>confirm</code> لسؤال المستخدم. قد يمثّل استخدام <code>link.getAttribute('href')‎</code> بدل <code>link.href</code> فكرة جيدة. انظر في الحل للتفاصيل.
</p>

<p>
	<a data-ss1613984917="1" data-ss1613985164="1" href="https://plnkr.co/edit/dFmfWhLtL4Gd4ryk?p=preview" rel="external nofollow">افتح الحل في البيئة التجريبية</a>.
</p>

<h3>
	معرض الصور
</h3>

<p>
	الأهمية: 5
</p>

<p>
	أنشئ معرضًا للصور بحيث تتغير الصورة الرئيسيّة بالنقر على الصور المصغّرة.
</p>

<p>
	كما هو مبيّن <a data-ss1613984917="1" data-ss1613985164="1" href="https://en.js.cx/task/image-gallery/solution/" rel="external nofollow">هنا</a>.
</p>

<p>
	ملاحظة: استخدم تفويض الأحداث.
</p>

<p>
	<a data-ss1613984917="1" data-ss1613985164="1" href="https://plnkr.co/edit/b8rcZiN2kqsbPyT0?p=preview" rel="external nofollow">أنجز التمرين في البيئة التجريبية</a>.
</p>

<h3>
	الحل
</h3>

<p>
	يكون الحل بإسناد معالج إلى الحاوي وتتبّع النقرات. فإذا كان النقر على الرابط <code>&lt;a&gt;</code>، فنغير <code>src</code> الخاصّة بـ <code>‎#largeImg</code> إلى <code>href</code> الخاصة بتلك الصورة المصغرة.
</p>

<p>
	<a data-ss1613984917="1" data-ss1613985164="1" href="https://plnkr.co/edit/swIOGZytjCu3Otsb?p=preview" rel="external nofollow">افتح الحل في البيئة التجريبية</a>.
</p>

<p>
	ترجمة -وبتصرف- للمقال <a data-ss1613984917="1" data-ss1613985164="1" href="https://javascript.info/default-browser-action" rel="external nofollow">Browser default actions</a> من سلسلة <a data-ss1613984917="1" data-ss1613985164="1" href="https://javascript.info/ui" rel="external nofollow">Browser: Document, Events, Interfaces</a> لصاحبها Ilya Kantor
</p>
]]></description><guid isPermaLink="false">1143</guid><pubDate>Mon, 01 Mar 2021 13:03:00 +0000</pubDate></item><item><title>&#x643;&#x64A;&#x641;&#x64A;&#x629; &#x62A;&#x641;&#x648;&#x64A;&#x636; &#x627;&#x644;&#x623;&#x62D;&#x62F;&#x627;&#x62B; &#x641;&#x64A; &#x627;&#x644;&#x645;&#x62A;&#x635;&#x641;&#x62D; &#x648;&#x645;&#x639;&#x627;&#x644;&#x62C;&#x62A;&#x647;&#x627; &#x639;&#x628;&#x631; &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A;</title><link>https://academy.hsoub.com/programming/javascript/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%AA%D9%81%D9%88%D9%8A%D8%B6-%D8%A7%D9%84%D8%A3%D8%AD%D8%AF%D8%A7%D8%AB-%D9%81%D9%8A-%D8%A7%D9%84%D9%85%D8%AA%D8%B5%D9%81%D8%AD-%D9%88%D9%85%D8%B9%D8%A7%D9%84%D8%AC%D8%AA%D9%87%D8%A7-%D8%B9%D8%A8%D8%B1-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r1142/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_02/3.png.9c4424c3ed4dbf945728a6c99301f71f.png" /></p>

<p>
	يمكّننا انتشار اﻷحداث نحو اﻷسفل واﻷعلى من تطبيق أحد أقوى أنماط معالجة الأحداث، وهو ما يُسمى <em>تفويض الأحداث</em> (event delegation).
</p>

<p>
	تتلخّص الفكرة في أنه إذا كان لدينا الكثير من العناصر التي تُعالج بطريقة متماثلة، فبدل أن نسند معالجا لكلّ منها، فإنّنا نسند معالجا واحدا إلى السلف الذي يلتقون فيه.
</p>

<p>
	في داخل المعالج، يمكن أن نتعرّف على مكان وقوع الحدث من خلال <code>event.target</code>، ثم نعالجه.
</p>

<p>
	لنرى مثالا على ذلك -- <a data-ss1613984076="1" href="https://ar.m.wikipedia.org/wiki/%D8%A8%D8%A7%D9%83%D9%88%D8%A7" rel="external nofollow">مخطط باكوا</a> الذي يعكس الفلسفة الصينية القديمة، كما هو مبيّن من <a data-ss1613984076="1" href="https://en.js.cx/article/event-delegation/bagua/" rel="external nofollow">هنا</a>. ويمكن تمثيله بواسطة HTML كالتالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5503_7" style="">
<span class="tag">&lt;table&gt;</span><span class="pln">
  </span><span class="tag">&lt;tr&gt;</span><span class="pln">
    </span><span class="tag">&lt;th</span><span class="pln"> </span><span class="atn">colspan</span><span class="pun">=</span><span class="atv">"3"</span><span class="tag">&gt;&lt;em&gt;</span><span class="pln">Bagua</span><span class="tag">&lt;/em&gt;</span><span class="pln"> Chart: Direction, Element, Color, Meaning</span><span class="tag">&lt;/th&gt;</span><span class="pln">
  </span><span class="tag">&lt;/tr&gt;</span><span class="pln">
  </span><span class="tag">&lt;tr&gt;</span><span class="pln">
    </span><span class="tag">&lt;td</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"nw"</span><span class="tag">&gt;&lt;strong&gt;</span><span class="pln">Northwest</span><span class="tag">&lt;/strong&gt;&lt;br&gt;</span><span class="pln">Metal</span><span class="tag">&lt;br&gt;</span><span class="pln">Silver</span><span class="tag">&lt;br&gt;</span><span class="pln">Elders</span><span class="tag">&lt;/td&gt;</span><span class="pln">
    </span><span class="tag">&lt;td</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"n"</span><span class="tag">&gt;</span><span class="pln">...</span><span class="tag">&lt;/td&gt;</span><span class="pln">
    </span><span class="tag">&lt;td</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"ne"</span><span class="tag">&gt;</span><span class="pln">...</span><span class="tag">&lt;/td&gt;</span><span class="pln">
  </span><span class="tag">&lt;/tr&gt;</span><span class="pln">
  </span><span class="tag">&lt;tr&gt;</span><span class="pln">...2 more lines of this kind...</span><span class="tag">&lt;/tr&gt;</span><span class="pln">
  </span><span class="tag">&lt;tr&gt;</span><span class="pln">...2 more lines of this kind...</span><span class="tag">&lt;/tr&gt;</span><span class="pln">
</span><span class="tag">&lt;/table&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" data-ss1613984076="1" frameborder="no" height="265" loading="lazy" scrolling="no" src="https://codepen.io/Hsoub/embed/dyOVRWq?height=265&amp;theme-id=light&amp;default-tab=result" style="width: 100%;" title="JS-p2-event-delegation -ex1">See the Pen JS-p2-event-delegation -ex1 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	يحتوي الجدول على 9 خانات، لكنها قد تكون 99 أو 9999، لا يهمّ ذلك.
</p>

<p>
	<strong>مهمّتنا هي إبراز الخانة عند النقر عليها.</strong>
</p>

<p>
	بدل إسناد معالج <code>onclick</code> إلى كلّ <code>&lt;td&gt;</code> (قد يكون هناك الكثير منها)، سنسند المعالج "catch-all" إلى العنصر <code>&lt;table&gt;</code>.
</p>

<p>
	يستخدم المعالجُ الخاصيّة <code>event.target</code> للحصول على العنصر الذي نُقر عليه ثم يبرزه.
</p>

<p>
	إليك الشيفرة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5503_9" style="">
<span class="pln">let selectedTd</span><span class="pun">;</span><span class="pln">

table</span><span class="pun">.</span><span class="pln">onclick </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  let target </span><span class="pun">=</span><span class="pln"> event</span><span class="pun">.</span><span class="pln">target</span><span class="pun">;</span><span class="pln"> </span><span class="com">// أين كان النقر؟</span><span class="pln">

  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">target</span><span class="pun">.</span><span class="pln">tagName </span><span class="pun">!=</span><span class="pln"> </span><span class="str">'TD'</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">return</span><span class="pun">;</span><span class="pln"> </span><span class="com">// ؟ إذًا لا يهمّنا ذلك TD ليس في</span><span class="pln">

  highlight</span><span class="pun">(</span><span class="pln">target</span><span class="pun">);</span><span class="pln"> </span><span class="com">// أبرزه</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> highlight</span><span class="pun">(</span><span class="pln">td</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">selectedTd</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="com">// أزل الإبراز الحالي إن وُجد</span><span class="pln">
    selectedTd</span><span class="pun">.</span><span class="pln">classList</span><span class="pun">.</span><span class="pln">remove</span><span class="pun">(</span><span class="str">'highlight'</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
  selectedTd </span><span class="pun">=</span><span class="pln"> td</span><span class="pun">;</span><span class="pln">
  selectedTd</span><span class="pun">.</span><span class="pln">classList</span><span class="pun">.</span><span class="pln">add</span><span class="pun">(</span><span class="str">'highlight'</span><span class="pun">);</span><span class="pln"> </span><span class="com">// الجديدة td أبرز الـ</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لا تكترث هذه الشيفرة بعدد الخانات التي في الجدول. يمكننا إضافة وإزالة الخانات <code>&lt;td&gt;</code> ديناميكيا في أي وقت، وستظل وظيفة الإبراز تعمل.
</p>

<p>
	لكن تبقى هناك نقيصة. قد لا يقع النقر على العنصر <code>&lt;td&gt;</code> بعينه ولكن على عنصر آخر بداخله. ففي حالتنا هذه، لو ألقينا نظرة داخل HTML، سنلاحظ أوسمة مدرجة داخل <code>&lt;td&gt;</code>، مثل <code>&lt;strong&gt;</code>:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5503_11" style="">
<span class="tag">&lt;td&gt;</span><span class="pln">
  </span><span class="tag">&lt;strong&gt;</span><span class="pln">Northwest</span><span class="tag">&lt;/strong&gt;</span><span class="pln">
  ...
</span><span class="tag">&lt;/td&gt;</span></pre>

<p>
	فمن الطبيعي أنه لو وقع النقر على <code>&lt;strong&gt;</code>، فسيصير هو القيمة التي يحملها <code>event.target</code>.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-ss1613984076="1" href="https://academy.hsoub.com/uploads/monthly_2021_02/bagua-bubble.png.927fa5faca5a24225e3b8dde2ea21ec0.png" data-fileid="58078" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="58078" data-unique="s5hyadjbc" src="https://academy.hsoub.com/uploads/monthly_2021_02/bagua-bubble.png.927fa5faca5a24225e3b8dde2ea21ec0.png" alt="bagua-bubble.png"></a>
</p>

<p>
	داخل المعالج <code>table.onclick</code>، ينبغي علينا أن نأخذ <code>event.target</code> ونتحقق إن كان النقر قد وقع داخل <code>&lt;td&gt;</code> أو لا.
</p>

<p>
	هذه هي الشيفرة المحسّنة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5503_13" style="">
<span class="pln">table</span><span class="pun">.</span><span class="pln">onclick </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  let td </span><span class="pun">=</span><span class="pln"> event</span><span class="pun">.</span><span class="pln">target</span><span class="pun">.</span><span class="pln">closest</span><span class="pun">(</span><span class="str">'td'</span><span class="pun">);</span><span class="pln"> </span><span class="com">// (1)</span><span class="pln">

  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(!</span><span class="pln">td</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">return</span><span class="pun">;</span><span class="pln"> </span><span class="com">// (2)</span><span class="pln">

  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(!</span><span class="pln">table</span><span class="pun">.</span><span class="pln">contains</span><span class="pun">(</span><span class="pln">td</span><span class="pun">))</span><span class="pln"> </span><span class="kwd">return</span><span class="pun">;</span><span class="pln"> </span><span class="com">// (3)</span><span class="pln">

  highlight</span><span class="pun">(</span><span class="pln">td</span><span class="pun">);</span><span class="pln"> </span><span class="com">// (4)</span><span class="pln">
</span><span class="pun">};</span></pre>

<p>
	إليك بعض الإيضاحات:
</p>

<ol>
<li>
		يعيد التابع <code>elem.closest(selector)‎</code> أقرب سلف يطابق المُحدِّد selector. في حالتنا، نبحث عن أقرب <code>&lt;td&gt;</code> نصادفه صعودًا من العنصر المصدري.
	</li>
	<li>
		إذا لم يكن <code>event.target</code> بداخل أيّ <code>&lt;td&gt;</code>، فسيُعاد الاستدعاء مباشرة، إذ ليس هناك شيء لفعله.
	</li>
	<li>
		في حال تداخل الجداول، قد تكون <code>event.target</code> هي <code>&lt;td&gt;</code>، لكنّها موجودة خارج الجدول الحاليّ. فنتحقق إذًا من أنّ <code>&lt;td&gt;</code> خاصّة بجدولنا الحاليّ.
	</li>
	<li>
		وإذا كانت كذلك، نبرزها.
	</li>
</ol>
<p>
	وبذلك، تكون لدينا شيفرة سريعة وفعّالة للإبراز، لا تكترث بعدد الخانات التي في الجدول.
</p>

<h2>
	مثال عن التفويض: الأفعال داخل الترميز (markup)
</h2>

<p>
	هناك استعمالات أخرى لتفويض الأحداث.
</p>

<p>
	لنقُل أننا نود إنشاء قائمة من الأزرار: "حفظ" و "تحميل" و "بحث" وغير ذلك. ويوجد هناك كائن له التوابع <code>save</code> و <code>load</code> و <code>search</code> … فكيف يتم الربط بين هذه التوابع واﻷزرار؟
</p>

<p>
	أوّل ما قد يتبادر إلى الذهن هو إسناد معالج إلى كلّ زر. ولكنّ هناك حلًّا أكثر أناقة. يمكننا إسناد معالج إلى القائمة بأكملها و إضافة سمات <code>data-action</code> للأزرار تحمل التابع الذي سيُستدعى:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5503_15" style="">
<span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">data-action</span><span class="pun">=</span><span class="atv">"save"</span><span class="tag">&gt;</span><span class="pln">Click to Save</span><span class="tag">&lt;/button&gt;</span></pre>

<p>
	يقرأ المعالج السمة، وينفّذ التابع. ألقِ نظرة على المثال أدناه:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5503_17" style="">
<span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"menu"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">data-action</span><span class="pun">=</span><span class="atv">"save"</span><span class="tag">&gt;</span><span class="pln">Save</span><span class="tag">&lt;/button&gt;</span><span class="pln">
  </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">data-action</span><span class="pun">=</span><span class="atv">"load"</span><span class="tag">&gt;</span><span class="pln">Load</span><span class="tag">&lt;/button&gt;</span><span class="pln">
  </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">data-action</span><span class="pun">=</span><span class="atv">"search"</span><span class="tag">&gt;</span><span class="pln">Search</span><span class="tag">&lt;/button&gt;</span><span class="pln">
</span><span class="tag">&lt;/div&gt;</span><span class="pln">

</span><span class="tag">&lt;script&gt;</span><span class="pln">
  </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Menu</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    constructor</span><span class="pun">(</span><span class="pln">elem</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">_elem </span><span class="pun">=</span><span class="pln"> elem</span><span class="pun">;</span><span class="pln">
      elem</span><span class="pun">.</span><span class="pln">onclick </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">onClick</span><span class="pun">.</span><span class="pln">bind</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">);</span><span class="pln"> </span><span class="com">// (*)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    save</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      alert</span><span class="pun">(</span><span class="str">'saving'</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    load</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      alert</span><span class="pun">(</span><span class="str">'loading'</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    search</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      alert</span><span class="pun">(</span><span class="str">'searching'</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    onClick</span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      let action </span><span class="pun">=</span><span class="pln"> event</span><span class="pun">.</span><span class="pln">target</span><span class="pun">.</span><span class="pln">dataset</span><span class="pun">.</span><span class="pln">action</span><span class="pun">;</span><span class="pln">
      </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">action</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">[</span><span class="pln">action</span><span class="pun">]();</span><span class="pln">
      </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">};</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Menu</span><span class="pun">(</span><span class="pln">menu</span><span class="pun">);</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" data-ss1613984076="1" frameborder="no" height="265" loading="lazy" scrolling="no" src="https://codepen.io/Hsoub/embed/VwmMWbE?height=265&amp;theme-id=light&amp;default-tab=result" style="width: 100%;" title="JS-p2-event-delegation -ex2">See the Pen JS-p2-event-delegation -ex2 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	يُرجى ملاحظة أن <code>this.onClick</code> مرتبط بـ <code>this</code> في <code>(*)</code>. هذا مهمّ، لأنّه لو لم يكن كذلك فإن <code>this</code> الذي بداخله سيشير إلى عنصر (<code>elem</code>) ، وليس الكائن <code>Menu</code>، ولا يكون بذلك <code>this[action]‎</code> هو ما نحتاجه.
</p>

<p>
	فما هي إذًا المزايا التي يقدّمها تفويض الأحداث هنا؟
</p>

<ul>
<li>
		لا نحتاج كتابة شيفرة لإسناد معالج لكل زر. بل ننشئ فقط تابعًا ونضعه في الترميز.
	</li>
	<li>
		تصبح بنية HTML مرنة، فيمكننا إضافة وإزالة أزرار بسهولة.
	</li>
</ul>
<p>
	يمكننا أيضا استخدام أصناف مثل <code>‎.action-save</code> و <code>‎.action-load</code>، لكن سمة مثل <code>data-action</code> أفضل من الناحية الدلالية، بالإضافة إلى إمكانية استخدامها في قواعد CSS.
</p>

<h2>
	نمط "السلوك"
</h2>

<p>
	يمكننا أيضا استخدام تفويض الأحداث لإضافة "سلوكيّات" للعناصر <em>تصريحيًّا</em>، بواسطة سمات وأصناف خاصة.
</p>

<p>
	يتألّف هذا النمط من جزأين:
</p>

<ol>
<li>
		نضيف سمة مخصّصة إلى العنصر تعبّر عن سلوكه.
	</li>
	<li>
		يتتبع الأحداثَ معالجٌ على نطاق المستند، فإذا وقع حدث على عنصر له سمة، فإنه يقوم بالفعل المناسب.
	</li>
</ol>
<h3>
	مثال عن السلوك: العداد
</h3>

<p>
	على سبيل المثال، تضيف السمة <code>data-counter</code> هنا سلوك "زيادة القيمة عند النقر" للأزرار:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5503_19" style="">
<span class="typ">Counter</span><span class="pun">:</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">input type</span><span class="pun">=</span><span class="str">"button"</span><span class="pln"> value</span><span class="pun">=</span><span class="str">"1"</span><span class="pln"> data</span><span class="pun">-</span><span class="pln">counter</span><span class="pun">&gt;</span><span class="pln">
</span><span class="typ">One</span><span class="pln"> more counter</span><span class="pun">:</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">input type</span><span class="pun">=</span><span class="str">"button"</span><span class="pln"> value</span><span class="pun">=</span><span class="str">"2"</span><span class="pln"> data</span><span class="pun">-</span><span class="pln">counter</span><span class="pun">&gt;</span><span class="pln">

</span><span class="pun">&lt;</span><span class="pln">script</span><span class="pun">&gt;</span><span class="pln">
  document</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">'click'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">event</span><span class="pun">.</span><span class="pln">target</span><span class="pun">.</span><span class="pln">dataset</span><span class="pun">.</span><span class="pln">counter </span><span class="pun">!=</span><span class="pln"> </span><span class="kwd">undefined</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="com">// إذا كانت السمة موجودة...</span><span class="pln">
      event</span><span class="pun">.</span><span class="pln">target</span><span class="pun">.</span><span class="pln">value</span><span class="pun">++;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

  </span><span class="pun">});</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" data-ss1613984076="1" frameborder="no" height="265" loading="lazy" scrolling="no" src="https://codepen.io/Hsoub/embed/bGBoRad?height=265&amp;theme-id=light&amp;default-tab=result" style="width: 100%;" title="JS-p2-event-delegation -ex3">See the Pen JS-p2-event-delegation -ex3 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	إذا نقرنا على أحد الأزرار، فإن القيمة التي عليه ستزداد. بغضّ النظر عن هذه الأزرار، فإن المنهجية العامة المتبعة هنا مهمّة.
</p>

<p>
	يمكن أن يكون هناك من السمات مع <code>data-counter</code> بقدر ما نرغب. يمكننا إضافة سمات جديدة إلى HTML في أي وقت. باستخدام تفويض الأحداث، نكون قد "وسّعنا" HTML من خلال إضافة سمة تعبّر عن سلوك جديد.
</p>

<hr>
<p>
	<strong>تنبيه: استخدم دائما <code>addEventListener</code> في المعالجات التي على مستوى المستند</strong>
</p>

<p>
	عند إسناد معالج حدثٍ إلى الكائن <code>document</code>، يجب أن نستخدم دائما <code>addEventListener</code>، وليس <code>document.on&lt;event&gt;‎</code>، لأن هذا الأخير سيؤدي إلى تعارضات: تستبدل المعالجاتُ الجديدة المعالجات القديمة.
</p>

<p>
	في المشاريع الواقعية، من الطبيعي أن تكون هناك عدة معالجات قد أُسندت بواسطة أجزاء مختلفة من الشيفرة.
</p>

<hr>
<h3>
	مثال عن السلوك: القالِب (toggler)
</h3>

<p>
	لنرى مثالا آخر عن السلوك. يؤدي النقر على عنصرٍ له السمة <code>data-toggle-id</code> إلى إخفاء وإظهار العنصر الذي له ذاك الـ <code>id</code>.
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5503_21" style="">
<span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">data-toggle-id</span><span class="pun">=</span><span class="atv">"subscribe-mail"</span><span class="tag">&gt;</span><span class="pln">
  Show the subscription form
</span><span class="tag">&lt;/button&gt;</span><span class="pln">

</span><span class="tag">&lt;form</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"subscribe-mail"</span><span class="pln"> </span><span class="atn">hidden</span><span class="tag">&gt;</span><span class="pln">
  Your mail: </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"email"</span><span class="tag">&gt;</span><span class="pln">
</span><span class="tag">&lt;/form&gt;</span><span class="pln">

</span><span class="tag">&lt;script&gt;</span><span class="pln">
  document</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">'click'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let id </span><span class="pun">=</span><span class="pln"> event</span><span class="pun">.</span><span class="pln">target</span><span class="pun">.</span><span class="pln">dataset</span><span class="pun">.</span><span class="pln">toggleId</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(!</span><span class="pln">id</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">return</span><span class="pun">;</span><span class="pln">

    let elem </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="pln">id</span><span class="pun">);</span><span class="pln">

    elem</span><span class="pun">.</span><span class="pln">hidden </span><span class="pun">=</span><span class="pln"> </span><span class="pun">!</span><span class="pln">elem</span><span class="pun">.</span><span class="pln">hidden</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">});</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" data-ss1613984076="1" frameborder="no" height="265" loading="lazy" scrolling="no" src="https://codepen.io/Hsoub/embed/yLVzXpg?height=265&amp;theme-id=light&amp;default-tab=result" style="width: 100%;" title="JS-p2-event-delegation -ex4">See the Pen JS-p2-event-delegation -ex4 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	لنلاحظ مرة أخرى ما قمنا به. لإضافة وظيفة القلب إلى عنصرٍ ما من الآن فصاعدًا، لا حاجة لمعرفة جافاسكربت، يكفي استخدام السمة <code>data-toggle-id</code>.
</p>

<p>
	قد يصير هذا ملائما بالفعل -- لا حاجة لكتابة جافاسكربت لكل واحد من هذه العناصر. يكفي استخدام السلوك فقط. يجعل المعالج الذي على مستوى المستند ذلك يعمل مع أي عنصر على الصفحة.
</p>

<p>
	يمكننا أن نجمع بين عدّة معالجات في نفس العنصر أيضا.
</p>

<p>
	قد يشكل نمط "السلوك" بديلا عن الأجزاء المصغرة (mini-fragments) في جافاسكربت.
</p>

<h2>
	الملخص
</h2>

<p>
	تفويض الأحداث رائع حقًّا! إذ يُعدّ واحدا من أنفع الأنماط المتعلّقة بأحداث DOM.
</p>

<p>
	كثيرا ما يُستخدم تفويض اﻷحداث لإضافة نفس المعالج لعدّة عناصر متماثلة، لكن لا يقتصر اﻷمر على ذلك.
</p>

<p>
	الخوارزمية:
</p>

<ol>
<li>
		أسند معالجًا وحيدًا إلى العنصر الحاوي.
	</li>
	<li>
		في المعالج -- افحص العنصر المصدري <code>event.target</code>.
	</li>
	<li>
		إذا وقع الحدث داخل عنصر يهمّنا، عالج الحدث.
	</li>
</ol>
<p>
	المزايا:
</p>

<ul>
<li>
		يبسّط التهيئة ويوفّر الذاكرة: لا حاجة لإضافة عدة معالجات.
	</li>
	<li>
		أقلّ شيفرة: عند إضافة أو إزالة عناصر، لا داعي لإضافة أو إزالة المعالجات.
	</li>
	<li>
		التعديلات على DOM: يمكننا إضافة أو إزالة العناصر جماعيا بواسطة <code>innerHTML</code> وما إلى ذلك.
	</li>
</ul>
<p>
	للتفويض حدود أيضا بالطبع:
</p>

<ul>
<li>
		أولًا، يجب أن يكون الحدث منتشرًا نحو اﻷعلى. بعض الأحداث لا تنتشر نحو اﻷعلى. يجب كذلك أن لا تَستخدم المعالجاتُ التي في الأسفل <code>event.stopPropagation()‎</code>.
	</li>
	<li>
		ثانيًا، قد يضيف التفويض عبئًا على وحدة المعالجة المركزية (CPU)، لأنّ المعالج الذي على مستوى الحاوي يستجيب للأحداث في أي مكان في الحاوي، بغضّ النظر عن كونها مهمّة لنا أو لا. لكن العبئ عادةً طفيف، فلا نأخذه بالحسبان.
	</li>
</ul>
<h2>
	التمارين
</h2>

<h3>
	أخفي الرسائل باستخدام التفويض
</h3>

<p>
	الأهمية: 5
</p>

<p>
	هناك قائمة من الرسائل لها أزرار لإزالتها <code>[x]</code>. اجعل الأزرار تعمل.
</p>

<p>
	كما هو مبيّن <a data-ss1613984076="1" href="https://en.js.cx/task/hide-message-delegate/solution/" rel="external nofollow">هنا</a>.
</p>

<p>
	ملاحظة: يجب أن يكون هناك منصت واحد للأحداث على الحاوي. استخدم تفويض الأحداث.
</p>

<p>
	<a data-ss1613984076="1" href="https://plnkr.co/edit/yJWlA1LCUowhwVGG?p=preview" rel="external nofollow">أنجز التمرين في البيئة التجريبية</a>
</p>

<h3>
	الحل
</h3>

<p>
	<a data-ss1613984076="1" href="https://plnkr.co/edit/06hFpY54nWey2nDO?p=preview" rel="external nofollow">افتح الحل في البيئة التجريبية</a>
</p>

<h3>
	قائمة شجرية
</h3>

<p>
	الأهمية: 5
</p>

<p>
	أنشئ شجرة يمكن فيها إظهار وإخفاء العقد الأبناء بواسطة النقر:
</p>

<p>
	كما هو مبيّن <a data-ss1613984076="1" href="https://en.js.cx/task/sliding-tree/solution/" rel="external nofollow">هنا</a>.
</p>

<p>
	المتطلبات:
</p>

<ul>
<li>
		معالج واحد للأحداث فقط (استخدم التفويض).
	</li>
	<li>
		يجب ألا يفعل النقر خارج عقدة العنوان (في مساحة فارغة) أي شيء.
	</li>
</ul>
<p>
	<a data-ss1613984076="1" href="https://plnkr.co/edit/zQFuLhTPX4lkrokp?p=preview" rel="external nofollow">أنجز التمرين في البيئة التجريبية</a>
</p>

<h3>
	الحل
</h3>

<p>
	ينقسم الحل إلى جزئين:
</p>

<ol>
<li>
		ضع كلّ عقدة عنوان في الشجرة داخل <code>&lt;span&gt;</code>. بهذا يمكننا إضافة تنسيقات CSS إلى <code>:‎hover</code> و معالجة النقرات على النص بالضبط، لأن عُرض <code>&lt;span&gt;</code> هو نفس عُرض النص بالضبط (بخلاف ما لو كان بدونه).
	</li>
	<li>
		عيّن معالجًا على العقدة الجذر <code>tree</code>، وعالج النقرات على العنوانين <code>&lt;span&gt;</code> تلك.
	</li>
</ol>
<p>
	<a data-ss1613984076="1" href="https://plnkr.co/edit/efPMXY7fSzxUXW5H?p=preview" rel="external nofollow">افتح الحل في البيئة التجريبية</a>
</p>

<h3>
	جدول قابل للترتيب
</h3>

<p>
	الأهمية: 4
</p>

<p>
	اجعل الجدول قابلًا للترتيب: يجب أن يؤدي النقر على العناصر <code>&lt;th&gt;</code> إلى ترتيبه حسب العمود الموافق.
</p>

<p>
	لكلّ <code>&lt;th&gt;</code> نوع معين موجود بداخل السمة، هكذا:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5503_23" style="">
<span class="tag">&lt;table</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"grid"</span><span class="tag">&gt;</span><span class="pln">
 </span><span class="tag">&lt;thead&gt;</span><span class="pln">
  </span><span class="tag">&lt;tr&gt;</span><span class="pln">
   </span><span class="tag">&lt;th</span><span class="pln"> </span><span class="atn">data-type</span><span class="pun">=</span><span class="atv">"number"</span><span class="tag">&gt;</span><span class="pln">Age</span><span class="tag">&lt;/th&gt;</span><span class="pln">
   </span><span class="tag">&lt;th</span><span class="pln"> </span><span class="atn">data-type</span><span class="pun">=</span><span class="atv">"string"</span><span class="tag">&gt;</span><span class="pln">Name</span><span class="tag">&lt;/th&gt;</span><span class="pln">
  </span><span class="tag">&lt;/tr&gt;</span><span class="pln">
 </span><span class="tag">&lt;/thead&gt;</span><span class="pln">
 </span><span class="tag">&lt;tbody&gt;</span><span class="pln">
  </span><span class="tag">&lt;tr&gt;</span><span class="pln">
   </span><span class="tag">&lt;td&gt;</span><span class="pln">5</span><span class="tag">&lt;/td&gt;</span><span class="pln">
   </span><span class="tag">&lt;td&gt;</span><span class="pln">John</span><span class="tag">&lt;/td&gt;</span><span class="pln">
  </span><span class="tag">&lt;/tr&gt;</span><span class="pln">
  </span><span class="tag">&lt;tr&gt;</span><span class="pln">
   </span><span class="tag">&lt;td&gt;</span><span class="pln">10</span><span class="tag">&lt;/td&gt;</span><span class="pln">
   </span><span class="tag">&lt;td&gt;</span><span class="pln">Ann</span><span class="tag">&lt;/td&gt;</span><span class="pln">
  </span><span class="tag">&lt;/tr&gt;</span><span class="pln">
  ...
 </span><span class="tag">&lt;/tbody&gt;</span><span class="pln">
</span><span class="tag">&lt;/table&gt;</span></pre>

<p>
	في المثال أعلاه، يحتوي العمود الأول على الأرقام، و العمود الثاني على الحروف. يجب أن تقوم دالة الترتيب بمعالجة الترتيب حسب النوع.
</p>

<p>
	يستلزم فقط أن يُدعم النوعان <code>"string"</code> و <code>"number"</code>.
</p>

<p>
	يمكن مشاهدة المثال يعمل من <a data-ss1613984076="1" href="https://en.js.cx/task/sortable-table/solution/" rel="external nofollow">هنا</a>.
</p>

<p>
	ملاحظة: يمكن أن يكون الجدول كبيرا، بأي عدد من الأسطر والأعمدة.
</p>

<p>
	<a data-ss1613984076="1" href="https://plnkr.co/edit/Xy6bIm1THcPADrDN?p=preview" rel="external nofollow">أنجز التمرين في البيئة التجريبية</a>
</p>

<h3>
	الحل
</h3>

<p>
	<a data-ss1613984076="1" href="https://plnkr.co/edit/Xy6bIm1THcPADrDN?p=preview" rel="external nofollow">افتح الحل في البيئة التجريبية</a>
</p>

<h3>
	سلوك التلميحات
</h3>

<p>
	الأهمية: 5
</p>

<p>
	أنشئ شفرة جافاسكربت لأجل سلوك التلميحات (tooltips).
</p>

<p>
	عندما يحوم مؤشر الفأرة فوق عنصر له السمة <code>data-tooltip</code>، فيجب أن تظهر التلميحة فوقه، وعندما يفارقه فإنها تختفي.
</p>

<p>
	هذا مثال لشفرة HTML مع الشرح:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5503_25" style="">
<span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">data-tooltip</span><span class="pun">=</span><span class="atv">"the tooltip is longer than the element"</span><span class="tag">&gt;</span><span class="pln">Short button</span><span class="tag">&lt;/button&gt;</span><span class="pln">
&lt;button data-tooltip="HTML</span><span class="tag">&lt;br&gt;</span><span class="pln">tooltip"&gt;One more button</span><span class="tag">&lt;/button&gt;</span></pre>

<p>
	يجب أن تعمل كما <a data-ss1613984076="1" href="https://en.js.cx/task/behavior-tooltip/solution/" rel="external nofollow">هنا</a>.
</p>

<p>
	سنفترض في هذا التمرين أن جميع العناصر التي لها <code>data-tooltip</code> تحتوي على نص فقط. لا وسوم متداخلة (بعد).
</p>

<p>
	التفاصيل:
</p>

<ul>
<li>
		يجب أن تكون المسافة بين العنصر والتلميحة <code>5px</code>.
	</li>
	<li>
		يجب أن تكون التلميحة في منتصف العنصر، إن أمكن ذلك.
	</li>
	<li>
		يجب ألا تقطع التلميحة حوافّ النافذة. من المفترض أن تكون التلميحة فوق العنصر، فإذا كان العنصر في أعلى الصفحة ولا مكان هناك للتلميحة، فإنها تكون تحته.
	</li>
	<li>
		يُعطى محتوى التلميحة في السمة <code>data-tooltip</code>. يمكنها أن تحوي أي شفرة HTML.
	</li>
</ul>
<p>
	ستحتاج إلى حدثين هنا:
</p>

<ul>
<li>
		<p>
			<code>mouseover</code> يحصل عندما يحوم المؤشر فوق العنصر.
		</p>
	</li>
	<li>
		<p>
			<code>mouseout</code> يحصل عندما يفارق المؤشر العنصر.
		</p>
	</li>
</ul>
<p>
	يُرجى استخدام تفويض الأحداث: أسند اثنين من المعالجات إلى <code>document</code> لتتبّع كلّ "الحومان" و "المفارقة" للعناصر التي لها <code>data-tooltip</code> وقم بإدارة التلميحات من هناك.
</p>

<p>
	بعد تطبيق السلوك، يمكن ولو لأناس غير متعودين على جافاسكربت إضافة عناصر بتلميحات.
</p>

<p>
	ملاحظة: يجب أن تظهر تلميحة واحدة فقط في نفس الوقت.
</p>

<p>
	<a data-ss1613984076="1" href="https://plnkr.co/edit/qzyeY4q7GxRXgqc2?p=preview" rel="external nofollow">أنجز التمرين في البيئة التجريبية</a>
</p>

<h3>
	الحل
</h3>

<p>
	<a data-ss1613984076="1" href="https://plnkr.co/edit/YkcXZKcB8AUpLuZN?p=preview" rel="external nofollow">افتح الحل في البيئة التجريبية</a>
</p>

<p>
	ترجمة -وبتصرف- للمقال <a data-ss1613984076="1" href="https://javascript.info/event-delegation" rel="external nofollow">Event delegation</a> من سلسلة <a data-ss1613984076="1" href="https://javascript.info/ui" rel="external nofollow">Browser: Document, Events, Interfaces</a> لصاحبها Ilya Kantor
</p>
]]></description><guid isPermaLink="false">1142</guid><pubDate>Mon, 22 Feb 2021 08:57:09 +0000</pubDate></item><item><title>&#x641;&#x647;&#x645; &#x639;&#x645;&#x644;&#x64A;&#x629; &#x627;&#x646;&#x62A;&#x634;&#x627;&#x631; &#x627;&#x644;&#x623;&#x62D;&#x62F;&#x627;&#x62B; &#x641;&#x64A; &#x627;&#x644;&#x645;&#x62A;&#x635;&#x641;&#x62D; &#x648;&#x627;&#x644;&#x62A;&#x62D;&#x643;&#x645; &#x641;&#x64A;&#x647;&#x627; &#x639;&#x628;&#x631; &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A;</title><link>https://academy.hsoub.com/programming/javascript/%D9%81%D9%87%D9%85-%D8%B9%D9%85%D9%84%D9%8A%D8%A9-%D8%A7%D9%86%D8%AA%D8%B4%D8%A7%D8%B1-%D8%A7%D9%84%D8%A3%D8%AD%D8%AF%D8%A7%D8%AB-%D9%81%D9%8A-%D8%A7%D9%84%D9%85%D8%AA%D8%B5%D9%81%D8%AD-%D9%88%D8%A7%D9%84%D8%AA%D8%AD%D9%83%D9%85-%D9%81%D9%8A%D9%87%D8%A7-%D8%B9%D8%A8%D8%B1-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r1141/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_02/2.png.e5825ade6476b8063466a5f49c5e99a1.png" /></p>

<p>
	لنبتدئ بمثال. المعالج التالي مُسندٌ إلى العنصر <code>&lt;div&gt;</code>، لكنّه أيضًا يشتغل عند النقر على الوسوم الداخلة تحته مثل <code>&lt;em&gt;</code> أو <code>&lt;code&gt;</code>.
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5999_7" style="">
<span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">onclick</span><span class="pun">=</span><span class="atv">"</span><span class="pln">alert</span><span class="pun">(</span><span class="str">'The handler!'</span><span class="pun">)</span><span class="atv">"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;em&gt;</span><span class="pln">If you click on </span><span class="tag">&lt;code&gt;</span><span class="pln">EM</span><span class="tag">&lt;/code&gt;</span><span class="pln">, the handler on </span><span class="tag">&lt;code&gt;</span><span class="pln">DIV</span><span class="tag">&lt;/code&gt;</span><span class="pln"> runs.</span><span class="tag">&lt;/em&gt;</span><span class="pln">
</span><span class="tag">&lt;/div&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" data-ss1613983352="1" frameborder="no" height="265" loading="lazy" scrolling="no" src="https://codepen.io/Hsoub/embed/LYbzLxm?height=265&amp;theme-id=light&amp;default-tab=result" style="width: 100%;" title="JS-p2-bubbling-and-capturing -ex1">See the Pen JS-p2-bubbling-and-capturing -ex1 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	أليس هذا غريبًا بعض الشيء؟ لماذا يشتغل المعالج المُسنَد إلى <code>&lt;div&gt;</code> إذا كان النقر في الواقع على <code>&lt;em&gt;</code>؟
</p>

<h2>
	انتشار اﻷحداث نحو اﻷعلى
</h2>

<p>
	مبدأ الانتشار نحو اﻷعلى (bubbling) بسيط.
</p>

<p>
	<strong>عندما يقع حدثٌ على عنصرٍ ما، فإنّه يُشغّل المعالجات المسندة إليه، ثم المسندة إلى أبيه، وهكذا صعودًا إلى المعالجات المسندة إلى أسلافه الآخرين.</strong>
</p>

<p>
	لنفترض أنّ لدينا ثلاثة عناصر متداخلة <code>P &lt; DIV &lt; FORM</code> ، مع معالجٍ لكلّ منها:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5999_9" style="">
<span class="tag">&lt;style&gt;</span><span class="pln">
  body </span><span class="pun">*</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    margin</span><span class="pun">:</span><span class="pln"> </span><span class="lit">10px</span><span class="pun">;</span><span class="pln">
    border</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1px</span><span class="pln"> solid blue</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="tag">&lt;/style&gt;</span><span class="pln">

</span><span class="tag">&lt;form</span><span class="pln"> </span><span class="atn">onclick</span><span class="pun">=</span><span class="atv">"</span><span class="pln">alert</span><span class="pun">(</span><span class="str">'form'</span><span class="pun">)</span><span class="atv">"</span><span class="tag">&gt;</span><span class="pln">FORM
  </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">onclick</span><span class="pun">=</span><span class="atv">"</span><span class="pln">alert</span><span class="pun">(</span><span class="str">'div'</span><span class="pun">)</span><span class="atv">"</span><span class="tag">&gt;</span><span class="pln">DIV
    </span><span class="tag">&lt;p</span><span class="pln"> </span><span class="atn">onclick</span><span class="pun">=</span><span class="atv">"</span><span class="pln">alert</span><span class="pun">(</span><span class="str">'p'</span><span class="pun">)</span><span class="atv">"</span><span class="tag">&gt;</span><span class="pln">P</span><span class="tag">&lt;/p&gt;</span><span class="pln">
  </span><span class="tag">&lt;/div&gt;</span><span class="pln">
</span><span class="tag">&lt;/form&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" data-ss1613983352="1" frameborder="no" height="265" loading="lazy" scrolling="no" src="https://codepen.io/Hsoub/embed/VwmMWPG?height=265&amp;theme-id=light&amp;default-tab=result" style="width: 100%;" title="JS-p2-bubbling-and-capturing -ex2">See the Pen JS-p2-bubbling-and-capturing -ex2 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	يؤدّي النّقر على العنصر <code>&lt;p&gt;</code> الذي بالداخل أوّلًا إلى تشغيل <code>onclick</code> :
</p>

<ol>
<li>
		المُسند إلى <code>&lt;p&gt;</code> ذاك.
	</li>
	<li>
		ثم المُسند إلى <code>&lt;div&gt;</code> الذي خارجه.
	</li>
	<li>
		ثم المُسند إلى <code>&lt;form&gt;</code> الذي خارجه.
	</li>
	<li>
		وهكذا صعودًا إلى الكائن <code>document</code>.
	</li>
</ol>
<p style="text-align: center;">
	<img class="ipsImage ipsImage_thumbnailed" data-fileid="58076" data-unique="fu57mjhvj" src="https://academy.hsoub.com/uploads/monthly_2021_02/event-order-bubbling.png.e9de6330c237b41eb4a9fdbea08262bd.png" alt="event-order-bubbling.png"></p>

<p>
	فإذا نقرنا على <code>&lt;p&gt;</code> ، سنرى ثلاثة تنبيهات متتالية: <code>form</code> &lt;- <code>div</code> &lt;- <code>p</code>.
</p>

<p>
	تُعرف على هذه العمليّة بالانتشار نحو اﻷعلى (bubbling)، لأنّ الأحداث تنتشر من العنصر الداخلي صعودًا عبر آبائه كالفقّاعة في الماء.
</p>

<hr>
<p>
	<strong>تنبيه: تنتشر مُعظم اﻷحداث نحو اﻷعلى</strong>
</p>

<p>
	ينبغي التنبه في هذه الجملة إلى كلمة "مُعظم".
</p>

<p>
	على سبيل المثال، لا ينتشر الحدث <code>focus</code> نحو اﻷعلى. وسنرى أيضا أمثلة أخرى. لكنّها تبقى استثناءً عوض القاعدة، فمعظم اﻷحداث تنتشر نحو اﻷعلى.
</p>

<hr>
<h2>
	event.target
</h2>

<p>
	يمكن للمعالج المسند إلى عنصرٍ أبٍ أن يتحصّل دائمًا على تفاصيل مكان وقوع الحدث.
</p>

<p>
	<strong>يُسمّى العنصر اﻷدنى الذي نشأ عنه الحدث بالعنصر "الهدف"، ويمكن الوصول إليه بواسطة <code>event.target</code>.</strong>
</p>

<p>
	لاحظ الاختلاف الذي بينه و <code>this</code> (الذي هو نفس <code>event.currentTarget</code>):
</p>

<ul>
<li>
		<code>event.target</code> -- هو العنصر "الهدف" الذي أنشأ الحدث، ولا يتغيّر خلال عمليّة الانتشار نحو اﻷعلى.
	</li>
	<li>
		<code>this</code> -- هو العنصر "الحاليّ"، أي الذي أُسنِد إليه المعالجُ الذي يشتغل حاليّا.
	</li>
</ul>
<p>
	على سبيل المثال، إذا كان لدينا معالجٌ وحيدٌ <code>form.onclick</code> مُسندٌ إلى النموذج <code>&lt;form&gt;</code>، فإنّه يمكنه "التقاط" جميع النقرات داخل النموذج. أيّا كان مكان وقوعها، فإنّها تنتشر نحو اﻷعلى إلى <code>&lt;form&gt;</code> وتشغّل المعالج.
</p>

<p>
	في المعالج <code>form.onclick</code>:
</p>

<ul>
<li>
		<code>this</code> (الذي هو نفس <code>event.currentTarget</code>) هو العنصر <code>&lt;form&gt;</code>، لأنّ المعالج المُشتغل مسندٌ إليه.
	</li>
	<li>
		<code>event.target</code> هو العنصر الذي نُقر عليه داخل النموذج.
	</li>
</ul>
<p>
	يمكنك رؤية ذلك من <a data-ss1613983352="1" href="https://javascript.info/article/bubbling-and-capturing/bubble-target/" rel="external nofollow">هنا</a> ، من خلال النقر على مختلف العناصر لإظهار <code>event.target</code> و <code>this</code> في كلّ حالة.
</p>

<p>
	قد يكون <code>event.target</code> هو نفسه <code>this</code>، كما لو نقرنا هنا على العنصر <code>&lt;form&gt;</code> مباشرة.
</p>

<h2>
	إيقاف الانتشار نحو اﻷعلى
</h2>

<p>
	ينطلق الحدث عند انتشاره نحو اﻷعلى من العنصر الهدف مباشرة. ويواصل الانتشار عادةً إلى أن يصل إلى <code>&lt;html&gt;</code>، ومن ثَمّ إلى الكائن <code>document</code>، بل إنّ بعض اﻷحداث قد تصل إلى <code>window</code>، ويشغّل جميع المعالجات في طريقه إلى هناك.
</p>

<p>
	لكن قد يقرّر أحد المعالجات أن الحدث قد تمّت معالجته ويوقف بذلك عمليّة الانتشار.
</p>

<p>
	يتوقّف الانتشار نحو اﻷعلى بواسطة التابع <code>event.stopPropagation()</code>‎. على سبيل المثال، لا يشتغل المعالج <code>body.onclick</code> هنا عند النقر على <code>&lt;button&gt;</code>:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5999_11" style="">
<span class="tag">&lt;body</span><span class="pln"> </span><span class="atn">onclick</span><span class="pun">=</span><span class="atv">"</span><span class="pln">alert</span><span class="pun">(`</span><span class="pln">the bubbling doesn</span><span class="str">'t reach here`)</span><span class="atv">"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">onclick</span><span class="pun">=</span><span class="atv">"</span><span class="pln">event</span><span class="pun">.</span><span class="pln">stopPropagation</span><span class="pun">()</span><span class="atv">"</span><span class="tag">&gt;</span><span class="pln">Click me</span><span class="tag">&lt;/button&gt;</span><span class="pln">
</span><span class="tag">&lt;/body&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" data-ss1613983352="1" frameborder="no" height="265" loading="lazy" scrolling="no" src="https://codepen.io/Hsoub/embed/RwoLgKE?height=265&amp;theme-id=light&amp;default-tab=result" style="width: 100%;" title="JS-p2-bubbling-and-capturing -ex3">See the Pen JS-p2-bubbling-and-capturing -ex3 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<hr>
<p>
	<strong>ملاحظة: ()event.stopImmediatePropagation</strong>
</p>

<p>
	إذا أُسنِد إلى عنصرٍ ما عدّةُ معالجات لنفس الحدث، فحتىّ لو أوقف أحدها الانتشار نحو اﻷعلى، ستشتغل المعالجات الأخرى.
</p>

<p>
	بعبارة أخرى، يوقِف التابع <code>event.stopPropagation()‎‎</code> الانتشار نحو اﻷعلى، لكن ستشتغل بقيّة المعالجات المسندة إلى العنصر الحاليّ.
</p>

<p>
	لإيقاف الانتشار نحو اﻷعلى، ومنع اشتغال بقيّة المعالجات المُسندة إلى العنصر الحاليّ أيضا، يوجد هناك تابع لذلك <code>event.stopImmediatePropagation()‎‎</code> لا يشتغل بعده معالج.
</p>

<hr>
<p>
	<strong>تنبيه: لا توقف الانتشار نحو اﻷعلى دون الحاجة لذلك!</strong>
</p>

<p>
	الانتشار نحو اﻷعلى أمرٌ ملائم. لا توقفه دون سبب وجيه، يكون واضحًا ومُمحصًّا هندسيًّا.
</p>

<p>
	قد يُحدث التابع <code>event.stopPropagation()‎‎</code> أحيانًا مزالق تتسبّب لاحقًا في مشاكل. على سبيل المثال:
</p>

<ol>
<li>
		ننشئ قائمة متداخلة. تعالج كلُّ قائمة داخليّة النقرات التي على عناصرها، وتستدعي<code>stopPropagation</code> لتفادي تفعيل القائمة الخارجيّة.
	</li>
	<li>
		نقرّر بعدها أن نلتقط جميع النقرات على النافذة، لتتبع سلوك المستخدمين (أين ينقر الناس). تقوم بعض أنظمة التحليل بذلك، وعادةً ما تستخدم الشيفرةُ التابعَ <code>document.addEventListener('click'…)‎‎</code> لالتقاط جميع النقرات.
	</li>
	<li>
		لن يعمل نظام التحليل على المساحة التي أوقف فيها انتشار النقرات نحو اﻷعلى بواسطة <code>stopPropagation</code>. فيكون بذلك لدينا "منطقة ميّتة" للأسف.
	</li>
</ol>
<p>
	لا توجد في العادة حاجة حقيقيّة لإيقاف الانتشار نحو اﻷعلى. فالمهام التي تبدو أنّها تتطلب ذلك يمكن حلّها بوسائل أخرى. من بين هذه الوسائل، استخدام اﻷحداث المخصّصة (custom events) التي سنتناولها لاحقا. يمكننا أيضا كتابة بياناتٍ على الكائن <code>event</code> في معالج وقراءتها في معالج آخر، ليتسنى بذلك تمرير معلومات إلى المعالجات المسندة إلى الآباء حول المعالجة التي تمت في اﻷسفل.
</p>

<hr>
<h2>
	الانتشار نحو الأسفل
</h2>

<p>
	توجد هناك مرحلة أخرى لمعالجة اﻷحداث يُطلق عليها "الانتشار نحو اﻷسفل" (capturing). من النادر استخدامها في شيفرات واقعيّة، لكنّها قد تكون مفيدة أحيانا.
</p>

<p>
	يصِف معيار <a data-ss1613983352="1" href="http://www.w3.org/TR/DOM-Level-3-Events/" rel="external nofollow">أحداث DOM</a> ثلاث مراحل لانتشار الأحداث:
</p>

<ol>
<li>
		مرحلة الانتشار نحو اﻷسفل (Capturing phase) - ينزل الحدث إلى العنصر.
	</li>
	<li>
		مرحلة الهدف (Target phase) - يصل الحدث إلى العنصر الهدف.
	</li>
	<li>
		مرحلة الانتشار نحو اﻷعلى (Bubbling phase) - ينتشر الحدث صعودًا من العنصر.
	</li>
</ol>
<p>
	هذه صورة لما يحصل عند النقر على <code>&lt;td&gt;</code> داخل جدول، مأخوذة من المواصفة:
</p>

<p style="text-align: center;">
	<img class="ipsImage ipsImage_thumbnailed" data-fileid="58077" data-unique="gzn3rb6g8" src="https://academy.hsoub.com/uploads/monthly_2021_02/eventflow.png.e67a5f4d01065d6566e41a1226745163.png" alt="eventflow.png"></p>

<p>
	ما يعني ذلك: بالنقر على <code>&lt;td&gt;</code> ، ينتشر الحدث أوّلا عبر سلسلة الأسلاف نزولًا إلى العنصر (مرحلة الانتشار نحو اﻷسفل)، فيبلغ الهدفَ ويتفعّل هناك (مرحلة الهدف)، ثم ينتشر صعودًا (مرحلة الانتشار نحو اﻷعلى) مستدعيًا المعالجات في طريقه.
</p>

<p>
	<strong>اقتصرنا في السابق على مرحلة الانتشار نحو اﻷعلى، لأنّه من النادر استخدام مرحلة الانتشار نحو اﻷسفل. لا تظهر لنا عادةً.</strong>
</p>

<p>
	لا يعلم المعالجون الذين عُيّنوا على شكل خاصيّة <code>on&lt;event&gt;‎‎</code> ، أو على شكل سمة HTML، أو باستخدام <code>addEventListener(event, handler)‎‎</code> بوسيطين فقط، شيئًا عن الانتشار نحو اﻷسفل، فهم يشتغلون فقط في المرحلتين الثانية والثالثة.
</p>

<p>
	لالتقاط حدثٍ في مرحلة الانتشار نحو اﻷسفل، يجب تغيير قيمة الخيار <code>capture</code> إلى <code>true</code>.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5999_13" style="">
<span class="pln">elem</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(...,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">capture</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">})</span><span class="pln">

</span><span class="com">//  {capture: true} فهو اختصار لـ ،"true" أو فقط</span><span class="pln">

elem</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(...,</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">)</span></pre>

<p>
	يمكن أن يأخذ الخيار <code>capture</code> قيمتين:
</p>

<ul>
<li>
		إذا كانت <code>false</code> (افتراضيًّا)، فإنّ المعالج يوضع في مرحلة الانتشار نحو اﻷعلى.
	</li>
	<li>
		إذا كانت <code>true</code>، فإنّ المعالج يوضع في مرحلة الانتشار نحو اﻷسفل.
	</li>
</ul>
<p>
	لاحظ رغم أنّه يوجد رسميًّا ثلاث مراحل، إلّا أن المرحلة الثانية (مرحلة الهدف: عندما يبلغ الحدثُ الهدف) لا تُعالَج بشكل مستقل، بل تشتغل كلٌّ من المعالجات الموضوعة في مرحلتي الانتشار نحو اﻷسفل واﻷعلى في هذه المرحلة أيضا.
</p>

<p>
	لنرى كلًّا من الانتشار نحو اﻷسفل والأعلى حال عملهما:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5999_15" style="">
<span class="tag">&lt;style&gt;</span><span class="pln">
  body </span><span class="pun">*</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    margin</span><span class="pun">:</span><span class="pln"> </span><span class="lit">10px</span><span class="pun">;</span><span class="pln">
    border</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1px</span><span class="pln"> solid blue</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="tag">&lt;/style&gt;</span><span class="pln">

</span><span class="tag">&lt;form&gt;</span><span class="pln">FORM
  </span><span class="tag">&lt;div&gt;</span><span class="pln">DIV
    </span><span class="tag">&lt;p&gt;</span><span class="pln">P</span><span class="tag">&lt;/p&gt;</span><span class="pln">
  </span><span class="tag">&lt;/div&gt;</span><span class="pln">
</span><span class="tag">&lt;/form&gt;</span><span class="pln">

</span><span class="tag">&lt;script&gt;</span><span class="pln">
  </span><span class="kwd">for</span><span class="pun">(</span><span class="pln">let elem of document</span><span class="pun">.</span><span class="pln">querySelectorAll</span><span class="pun">(</span><span class="str">'*'</span><span class="pun">))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    elem</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"click"</span><span class="pun">,</span><span class="pln"> e </span><span class="pun">=&gt;</span><span class="pln"> alert</span><span class="pun">(`</span><span class="typ">Capturing</span><span class="pun">:</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">elem</span><span class="pun">.</span><span class="pln">tagName</span><span class="pun">}`),</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">);</span><span class="pln">
    elem</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"click"</span><span class="pun">,</span><span class="pln"> e </span><span class="pun">=&gt;</span><span class="pln"> alert</span><span class="pun">(`</span><span class="typ">Bubbling</span><span class="pun">:</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">elem</span><span class="pun">.</span><span class="pln">tagName</span><span class="pun">}`));</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" data-ss1613983352="1" frameborder="no" height="265" loading="lazy" scrolling="no" src="https://codepen.io/Hsoub/embed/qBqPjmY?height=265&amp;theme-id=light&amp;default-tab=result" style="width: 100%;" title="JS-p2-bubbling-and-capturing -ex4">See the Pen JS-p2-bubbling-and-capturing -ex4 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	تُسند الشيفرة معالجاتٍ لحدث النّقر إلى <em>جميع</em> العناصر التي في المستند لرؤية أيّها تعمل.
</p>

<p>
	عند النقر على <code>&lt;p&gt;</code>، فإنّ التسلسل يكون كالتالي:
</p>

<ol>
<li>
		<code>DIV</code> ‹- <code>FORM</code> ‹- <code>BODY</code> ‹- <code>HTML</code> (مرحلة الانتشار نحو اﻷسفل، أوّل المنصتين).
	</li>
	<li>
		<code>P</code> (مرحلة الهدف، تُفعّل مرّتين لأنّنا وضعنا مُنصتَين اثنين: الانتشار نحو اﻷسفل واﻷعلى).
	</li>
	<li>
		<code>HTML</code> ‹- <code>BODY</code> ‹- <code>FORM</code> ‹- <code>DIV</code> (مرحلة الانتشار نحو اﻷسفل، ثاني المنصتين).
	</li>
</ol>
<p>
	توجد هناك الخاصيّة <code>event.eventPhase</code> التي تخبرنا برقم المرحلة التي تمّ فيها التقاط الحدث. لكن يندر استخدامها لأنّنا نعلم ذلك من خلال المعالج عادةً.
</p>

<hr>
<p>
	<strong>ملاحظة: لحذف المعالج، يستلزم التابع <code>removeEventListener</code> إعطاء نفس المرحلة</strong>
</p>

<p>
	عند إضافة معالجٍ بهذا الشكل <code>addEventListener(..., true)‎‎</code>، فيجب ذكر نفس المرحلة أيضًا في <code>removeEventListener(..., true)‎‎</code> لحذف المعالج بشكل صحيح.
</p>

<hr>
<p>
	<strong>ملاحظة: تشتغل المعالجات التي أُسندت إلى نفس العنصر وفي نفس المرحلة حسب الترتيب الذي أُنشئت به</strong>
</p>

<p>
	إذا كانت لدينا عدّة معالجات للأحداث مُسنَدة إلى نفس العنصر، وفي نفس المرحلة فإنها تشتغل بحسب الترتيب الذي أُنشئت به.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5999_17" style="">
<span class="pln">elem</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"click"</span><span class="pun">,</span><span class="pln"> e </span><span class="pun">=&gt;</span><span class="pln"> alert</span><span class="pun">(</span><span class="lit">1</span><span class="pun">));</span><span class="pln"> </span><span class="com">// من المؤكّد أن يشتغل أوّلا</span><span class="pln">
elem</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"click"</span><span class="pun">,</span><span class="pln"> e </span><span class="pun">=&gt;</span><span class="pln"> alert</span><span class="pun">(</span><span class="lit">2</span><span class="pun">));</span></pre>

<hr>
<h2>
	الملخص
</h2>

<p>
	عندما يقع الحدث، فإن أدنى العناصر الذي وقع فيه الحدث يُعلَّم بالعنصر"الهدف" (<code>event.target</code>).
</p>

<ul>
<li>
		<p>
			ثم ينتشر الحدث نزولًا من جذر المستند إلى <code>event.target</code> مستدعيًا في طريقه المعالجين المعيّنين بواسطة <code>addEventListener(..., true)‎‎</code> (القيمة ‎‎ <code>true</code> هي اختصار لـ <code>{capture: true}</code>)
		</p>
	</li>
	<li>
		<p>
			ثم نُستدعى المعالجات المُسندة إلى العنصر الهدف نفسه.
		</p>
	</li>
	<li>
		<p>
			ثم ينتشر الهدف صعودًا من <code>event.target</code> إلى الجذر، مناديًا المعالجات المعيّنة بواسطة <code>on&lt;event&gt;‎‎</code> و <code>addEventListener</code> دون الوسيط الثالث <code>false/{capture:false}‎‎</code>.
		</p>
	</li>
</ul>
<p>
	يمكن لأيّ معالجٍ أن يستخدم خاصيّات الكائن <code>event</code> التالية:
</p>

<ul>
<li>
		<code>event.target</code> -- أدنى العناصر الذي نشأ عنه الحدث.
	</li>
	<li>
		<code>event.currentTarget</code> (هو نفس <code>this</code>) -- العنصر الذي يعالج الحدث حاليًّا (الذي أُسند إليه المعالج).
	</li>
	<li>
		<code>event.eventPhase</code> -- المرحلة الحاليّة (1=الانتشار نحو اﻷسفل، 2=الهدف، 3=الانتشار نحو اﻷعلى).
	</li>
</ul>
<p>
	يمكن لأيّ معالجٍ أن يوقف انتشار الحدث من خلال استدعاء <code>event.stopPropagation()‎‎</code>، لكن لا يُنصح بذلك، لأنّه لا يمكن التأكّد حقًّا من عدم الحاجة إليه في الأعلى، ربّما في أمورٍ مختلفة تماما.
</p>

<p>
	يندر جدًّا استخدام مرحلة الانتشار نحو اﻷسفل، إذ تُعالَج الأحداث عادةً عند انتشارها نحو اﻷعلى. هناك سبب منطقي وراء ذلك.
</p>

<p>
	في الواقع، عندما يقع حادث ما، تُبلَّغ السلطات المحليّة أوّلًا. فهم أفضل من يعرف المنطقة التي وقع فيها الحادث. ثمّ تُبلّغ السلطات الأعلى عند الحاجة لذلك.
</p>

<p>
	ينطبق الأمر على معالجات الأحداث. تكون الشيفرة المسؤولة عن إسناد المعالج إلى عنصرٍ ما أعلم بالتفاصيل المتعلّقة بذلك العنصر ومالذي يفعله. فيكون المعالج المسند إلى العنصر<code>&lt;td&gt;</code> خصيصا أنسب بتولي أمر ذلك العنصر بالذات، إذ يعلم كلّ شيء بخصوصه، وينبغي أن تُمنح له الفرصة أوّلا. ثم يأتي أبوه المباشر، الذي يكون له اطّلاع على السياق لكنّه أقلّ معرفةً به. وهكذا إلى أعلى العناصر، الذي يعالج الأمور العامّة ويكون آخرهم اشتغالا.
</p>

<p>
	يرسي مفهوم الانتشار نحو اﻷسفل واﻷعلى اﻷساس لموضوع "تفويض الأحداث"، الذي يُعدّ نمط معالجةٍ للأحداث قويًّا للغاية. سندرسه في المقال التالي.
</p>

<p>
	ترجمة -وبتصرف- للمقال <a data-ss1613983352="1" href="https://javascript.info/bubbling-and-capturing" rel="external nofollow">Bubbling and capturing</a> من سلسلة <a data-ss1613983352="1" href="https://javascript.info/ui" rel="external nofollow">Browser: Document, Events, Interfaces</a> لصاحبها Ilya Kantor
</p>
]]></description><guid isPermaLink="false">1141</guid><pubDate>Mon, 22 Feb 2021 08:50:04 +0000</pubDate></item><item><title>&#x645;&#x62F;&#x62E;&#x644; &#x625;&#x644;&#x649; &#x623;&#x62D;&#x62F;&#x627;&#x62B; &#x627;&#x644;&#x645;&#x62A;&#x635;&#x641;&#x62D; &#x648;&#x643;&#x64A;&#x641;&#x64A;&#x629; &#x627;&#x644;&#x62A;&#x639;&#x627;&#x645;&#x644; &#x645;&#x639;&#x647;&#x627; &#x639;&#x628;&#x631; &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A;</title><link>https://academy.hsoub.com/programming/javascript/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A3%D8%AD%D8%AF%D8%A7%D8%AB-%D8%A7%D9%84%D9%85%D8%AA%D8%B5%D9%81%D8%AD-%D9%88%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9%D9%87%D8%A7-%D8%B9%D8%A8%D8%B1-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r1140/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_02/1.png.214817c0ef4a9c5ffe960d970ae76e02.png" /></p>

<p>
	تمثّل الأحداث (events) إشاراتٍ إلى أنّ شيئًا ما قد حصل. يمكن أن تنشأ هذه الإشارات من أيّ عقدة في DOM (لكنّها لا تقتصر فقط على DOM). على سبيل المثال، هذه قائمة لأكثر الأحداث فائدةً:
</p>

<p>
	<strong>أحداث الفأرة:</strong>
</p>

<ul>
<li>
		<p>
			<code>click</code> -- عند النقر بالفأرة على عنصرٍ ما (أو عند الضغط عليه باستخدام الأجهزة اللمسية)
		</p>
	</li>
	<li>
		<p>
			<code>contextmenu</code> -- عند النقر بالزرّ الأيمن للفأرة على عنصرٍ ما.
		</p>
	</li>
	<li>
		<p>
			<code>mouseout</code> \ <code>mouseover</code> -- عندما يبلغ / يغادر مؤشّر الفأرة عنصرًا ما.
		</p>
	</li>
	<li>
		<p>
			<code>mouseup</code> \ <code>mousedown</code> -- عند ضغط / تحرير زرّ الفأرة.
		</p>
	</li>
	<li>
		<p>
			<code>mousemove</code> -- عند تحريك مؤشّر الفأرة.
		</p>
	</li>
</ul>
<p>
	<strong>أحداث لوحة المفاتيح:</strong>
</p>

<ul>
<li>
		<code>keyup</code> \ <code>keydown</code> -- عند ضغط / إرسال أحد أزرار لوحة المفاتيح.
	</li>
</ul>
<p>
	<strong>أحداث النماذج:</strong>
</p>

<ul>
<li>
		<p>
			<code>submit</code> -- عندما يرسل المستخدم النموذج <code>&lt;form&gt;</code>.
		</p>
	</li>
	<li>
		<p>
			<code>focus</code> -- عندما يحدّد المستخدم عنصرًا ما في النموذج، كتحديده عنصر <code>&lt;input&gt;</code> مثلا.
		</p>
	</li>
</ul>
<p>
	<strong>أحداث المستند:</strong>
</p>

<ul>
<li>
		<code>DOMContentLoaded</code> -- عند الفراغ من تحميل ملف HTML ومعالجتِه، وبناء كامل شجرة DOM.
	</li>
</ul>
<p>
	<strong>الأحداث المتعلقة بـ CSS:</strong>
</p>

<ul>
<li>
		<code>transitionend</code> - عند انتهاء تحريكCSS (animation) ‎.
	</li>
</ul>
<p>
	وهناك العديد من الأحداث الأخرى، سنتناول بعضها بمزيدٍ من التفصيل في مقالاتٍ لاحقة.
</p>

<h2>
	معالجات الأحداث
</h2>

<p>
	من أجل الاستجابة للأحداث، يمكننا تعيين معالجٍ (handler) على شكل دالّة تُنفَّذ عند وقوع الحدث. وتُعدّ بذلك المعالجات وسيلةً لتنفيذ شيفرات جافاسكربت وفقًا لما يقوم به المستخدم.
</p>

<p>
	توجد عدة طرق لتعيين معالجٍ للحدث. سنتناولها بدءًا بأبسطها.
</p>

<h3>
	على شكل سمة HTML
</h3>

<p>
	يمكن تعيين المعالج في HTML على شكل سمةٍ (attribute) يكون اسمها على النحو <code>on&lt;event&gt;‎</code> أي on متبوعة باسم الحدث.
</p>

<p>
	على سبيل المثال، لتعيين معالجٍ لحدث <code>click</code> على عنصر <code>input</code>، يمكننا استخدام السمة <code>onclick</code> كالتالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_8776_86" style="">
<span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">value</span><span class="pun">=</span><span class="atv">"Click me!"</span><span class="pln"> </span><span class="atn">onclick</span><span class="pun">=</span><span class="atv">"</span><span class="pln">alert</span><span class="pun">(</span><span class="str">'Click!'</span><span class="pun">)</span><span class="atv">"</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"button"</span><span class="tag">&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" data-ss1613981987="1" data-ss1613982967="1" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-introduction-browser-events-ex1" src="https://codepen.io/Hsoub/embed/QWGqgNw?height=265&amp;theme-id=light&amp;default-tab=result">See the Pen JS-p2-introduction-browser-events-ex1 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	عند النقر بالفأرة، تُنفّذ الشيفرة التي بداخل <code>onclick</code>.
</p>

<p>
	يرجى التنبّه هنا إلى أنّنا استخدمنا علامات الاقتباس غير المزدوجة داخل <code>onclick</code>، لأنّ السّمة نفسها محاطة بعلامات اقتباس مزدوجة. فلو غفلنا عن أنّ الشيفرة موجودة داخل السّمة واستخدمنا داخلها علامات الاقتباس المزدوجة هكذا <code>onclick="alert("Click!")"‎</code> فلن تعمل الشيفرة بشكل صحيح.
</p>

<p>
	لا تعدّ سمة HTML مكانا مناسبا لكتابة الكثير من الشيفرة، فيحسُن إذًا أن ننشئ دالّة جافاسكربت ونستدعيها هناك.
</p>

<p>
	في المثال أدناه، يؤدي النقر إلى تنفيذ الدالّة <code>countRabbits()‎</code>
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_8776_88" style="">
<span class="tag">&lt;script&gt;</span><span class="pln">
  </span><span class="kwd">function</span><span class="pln"> countRabbits</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">for</span><span class="pun">(</span><span class="pln">let i</span><span class="pun">=</span><span class="lit">1</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">&lt;=</span><span class="lit">3</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      alert</span><span class="pun">(</span><span class="str">"Rabbit number "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> i</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span><span class="pln">

</span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"button"</span><span class="pln"> </span><span class="atn">onclick</span><span class="pun">=</span><span class="atv">"</span><span class="pln">countRabbits</span><span class="pun">()</span><span class="atv">"</span><span class="pln"> </span><span class="atn">value</span><span class="pun">=</span><span class="atv">"Count rabbits!"</span><span class="tag">&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" data-ss1613981987="1" data-ss1613982967="1" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-introduction-browser-events-ex2" src="https://codepen.io/Hsoub/embed/yLVzXaJ?height=265&amp;theme-id=light&amp;default-tab=html,result">See the Pen JS-p2-introduction-browser-events-ex2 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	كما هو معلوم، لا فرق بين الأحرف الكبيرة والصغيرة في تسمية سمات HTML، فتمثل كلّ من <code>ONCLICK</code> و <code>onClick</code> و <code>onCLICK</code> نفس السّمة، لكن في الغالب تُكتب السّمات بأحرف صغيرة هكذا <code>onclick</code>.
</p>

<h3>
	على شكل خاصيّة DOM
</h3>

<p>
	يمكننا تعيين معالجٍ على شكل خاصيّة DOM يكون اسمها على النحو <code>on&lt;event&gt;‎</code>. على سبيل المثال، <code>elem.onclick</code>:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_8776_90" style="">
<span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"elem"</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"button"</span><span class="pln"> </span><span class="atn">value</span><span class="pun">=</span><span class="atv">"Click me"</span><span class="tag">&gt;</span><span class="pln">
</span><span class="tag">&lt;script&gt;</span><span class="pln">
  elem</span><span class="pun">.</span><span class="pln">onclick </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    alert</span><span class="pun">(</span><span class="str">'Thank you'</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">};</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" data-ss1613981987="1" data-ss1613982967="1" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-introduction-browser-events-ex3" src="https://codepen.io/Hsoub/embed/oNYGwzd?height=265&amp;theme-id=light&amp;default-tab=html,result">See the Pen JS-p2-introduction-browser-events-ex3 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	عند تعيين المعالج على شكل سمة HTML، فإنّ المتصفّح يقرأها ثمّ يُنشئ من محتواها دالّة، ويكتبها على شكل خاصيّة في DOM. فتكون بذلك هذه الطريقة لتعيين المعالج مساوية للتي قبلها.
</p>

<p>
	تؤدي هاتان الشيفرتان الوظيفة نفسها:
</p>

<ol>
<li>
		مجرّد HTML:
	</li>
</ol>
<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_8776_92" style="">
<span class="pln">   </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"button"</span><span class="pln"> </span><span class="atn">onclick</span><span class="pun">=</span><span class="atv">"</span><span class="pln">alert</span><span class="pun">(</span><span class="str">'Click!'</span><span class="pun">)</span><span class="atv">"</span><span class="pln"> </span><span class="atn">value</span><span class="pun">=</span><span class="atv">"Button"</span><span class="tag">&gt;</span></pre>

<ol start="2">
<li>
		<p>
			HTML + JS:
		</p>

		<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_8776_94" style="">
<span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"button"</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"button"</span><span class="pln"> </span><span class="atn">value</span><span class="pun">=</span><span class="atv">"Button"</span><span class="tag">&gt;</span><span class="pln">
</span><span class="tag">&lt;script&gt;</span><span class="pln">
    button</span><span class="pun">.</span><span class="pln">onclick </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        alert</span><span class="pun">(</span><span class="str">'Click!'</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">};</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

		<p>
			 
		</p>
	</li>
</ol>
<p>
	استخدمنا في المثال الأوّل سمة HTML لتهيئة <code>button.onclick</code>، بينما في المثال الثاني استخدمنا سكربتًا لذلك. هذا الفرق الذي هناك.
</p>

<p>
	<strong>بما أنّ هناك خاصيّة واحدة فقط تحمل الاسم <code>onclick</code>، فلا يمكننا تعيين أكثر من معالج واحد لنفس الحدث.</strong>
</p>

<p>
	في المثال أدناه، تؤدي إضافة معالجٍ بواسطة جافاسكربت إلى استبدال المعالج الموجود مسبقًا.
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_8776_96" style="">
<span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"button"</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"elem"</span><span class="pln"> </span><span class="atn">onclick</span><span class="pun">=</span><span class="atv">"</span><span class="pln">alert</span><span class="pun">(</span><span class="str">'Before'</span><span class="pun">)</span><span class="atv">"</span><span class="pln"> </span><span class="atn">value</span><span class="pun">=</span><span class="atv">"Click me"</span><span class="tag">&gt;</span><span class="pln">
</span><span class="tag">&lt;script&gt;</span><span class="pln">
  elem</span><span class="pun">.</span><span class="pln">onclick </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="com">// يستبدل المعالج الموجود</span><span class="pln">
    alert</span><span class="pun">(</span><span class="str">'After'</span><span class="pun">);</span><span class="pln"> </span><span class="com">// هذا ما سيظهر فقط</span><span class="pln">
  </span><span class="pun">};</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" data-ss1613981987="1" data-ss1613982967="1" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-introduction-browser-events-ex4" src="https://codepen.io/Hsoub/embed/QWGqgGb?height=265&amp;theme-id=light&amp;default-tab=html,result">See the Pen JS-p2-introduction-browser-events-ex4 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	لحذف المعالج، يكفي إعطاء الخاصيّة القيمة <code>null</code> هكذا: <code>elem.onclick = null.</code>
</p>

<h2>
	الوصول إلى العنصر بواسطة this
</h2>

<p>
	تشير الكلمة <code>this</code> داخل المعالج إلى نفس العنصر الذي أُسند إليه المعالج. ففي الشيفرة أدناه، يُظهر العنصر <code>button</code> محتواه بواسطة <code>this.innerHTML</code>
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_8776_98" style="">
<span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">onclick</span><span class="pun">=</span><span class="atv">"</span><span class="pln">alert</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">innerHTML</span><span class="pun">)</span><span class="atv">"</span><span class="tag">&gt;</span><span class="pln">Click me</span><span class="tag">&lt;/button&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" data-ss1613981987="1" data-ss1613982967="1" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-introduction-browser-events-ex5" src="https://codepen.io/Hsoub/embed/yLVzXVJ?height=265&amp;theme-id=light&amp;default-tab=html,result">See the Pen JS-p2-introduction-browser-events-ex5 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<h2>
	أخطاء محتملة
</h2>

<p>
	في بداية التعامل مع معالجات الأحداث، يُرجى التنبه لعدد من الأمور الدقيقة.
</p>

<p>
	يمكن تعيين معالج من دالة موجودة مسبقا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8776_23" style="">
<span class="kwd">function</span><span class="pln"> sayThanks</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  alert</span><span class="pun">(</span><span class="str">'Thanks!'</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

elem</span><span class="pun">.</span><span class="pln">onclick </span><span class="pun">=</span><span class="pln"> sayThanks</span><span class="pun">;</span></pre>

<p>
	لكن انتبه، يجب إسناد الدالة كـ <code>sayThanks</code> وليس <code>sayThanks()‎</code>.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8776_27" style="">
<span class="com">// صحيح</span><span class="pln">
button</span><span class="pun">.</span><span class="pln">onclick </span><span class="pun">=</span><span class="pln"> sayThanks</span><span class="pun">;</span><span class="pln">

</span><span class="com">// خطأ</span><span class="pln">
button</span><span class="pun">.</span><span class="pln">onclick </span><span class="pun">=</span><span class="pln"> sayThanks</span><span class="pun">();</span></pre>

<p>
	بإضافة الأقواس، تصير <code>sayThanks()‎</code> استدعاءًا للدالة. وبالتالي، يأخذ السطر الأخير ناتج تنفيذ الدالّة (الذي هو <code>undefined</code> بحكم أنّ الدالة لا تعيد أيّ شيء) ويضعه في <code>onclick</code>. هذا لا يصلح.
</p>

<p>
	… في المقابل، نحتاج في HTML إلى تضمين الأقواس:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8776_29" style="">
<span class="pun">&lt;</span><span class="pln">input type</span><span class="pun">=</span><span class="str">"button"</span><span class="pln"> id</span><span class="pun">=</span><span class="str">"button"</span><span class="pln"> onclick</span><span class="pun">=</span><span class="str">"sayThanks()"</span><span class="pun">&gt;</span></pre>

<p>
	يمكن توضيح سبب ذلك كالتالي: عندما يقرأ المتصفّح السّمة، فإنّه ينشئ معالجًا على شكل دالّة لها نفس محتوى هذه السّمة. فيقوم HTML الذي لدينا بإنشاء الخاصيّة التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8776_31" style="">
<span class="pln">button</span><span class="pun">.</span><span class="pln">onclick </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  sayThanks</span><span class="pun">();</span><span class="pln"> </span><span class="com">// &lt;--  يصير محتوى السّمة هنا</span><span class="pln">
</span><span class="pun">};</span></pre>

<p>
	<strong>لا تستخدم setAttribute لتعيين المعالجات.</strong>
</p>

<p>
	هذه الشيفرة لا تصلح:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8776_33" style="">
<span class="com">// إلى توليد أخطاء &lt;body&gt; يؤدي النفر على</span><span class="pln">
</span><span class="com">// بحكم أنّ السّمات هي سلاسل نصيّة، فتصير الدالة سلسلة نصيّة ايضا</span><span class="pln">
document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">setAttribute</span><span class="pun">(</span><span class="str">'onclick'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> alert</span><span class="pun">(</span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">});</span></pre>

<p>
	<strong>تفرّق خاصيّات DOM بين الأحرف الكبيرة والصغيرة.</strong>
</p>

<p>
	يجب تعيين المعالج في <code>elem.onclick</code> بدل <code>elem.ONCLICK</code> ، لأنّ خاصيّات DOM تفرُق معها الأحرف الكبيرة والصغيرة.
</p>

<h2>
	addEventListener
</h2>

<p>
	تكمن المشكلة الأساسية في طرق تعيين المعالج السالفة الذكر، في عدم إمكانيّة تعيين عدّة معالجات لحدث واحد.
</p>

<p>
	لنفترض أن جزءًا من الشيفرة التي لدينا يهدف إلى إبراز أحد الأزرار عند النقر عليه، بينما يهدف جزء آخر من الشيفرة إلى إظهار رسالة ما عند نفس النقرة.
</p>

<p>
	قد نودّ تعيين عدّة معالجات للحدث لتحقيق ذلك، لكن بإضافة خاصيّة جديدة إلى DOM، تُستبدل الخاصيّة الموجودة مسبقًا.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8776_35" style="">
<span class="pln">input</span><span class="pun">.</span><span class="pln">onclick </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> alert</span><span class="pun">(</span><span class="lit">1</span><span class="pun">);</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
</span><span class="com">// ...</span><span class="pln">
input</span><span class="pun">.</span><span class="pln">onclick </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> alert</span><span class="pun">(</span><span class="lit">2</span><span class="pun">);</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> </span><span class="com">// يستبدل المعالج السابق</span></pre>

<p>
	أدرك العاملون على معايير الويب هذه المشكلة منذ القدم، واقترحوا طريقة بديلة لإدارة معالجات الأحداث، وذلك بواسطة التوابع الخاصة <code>addEventListener</code> و <code>removeEventListener</code>. تكون صيغة إضافة معالجٍ فيها كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8776_37" style="">
<span class="pln">element</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="pln">event</span><span class="pun">,</span><span class="pln"> handler</span><span class="pun">,</span><span class="pln"> </span><span class="pun">[</span><span class="pln">options</span><span class="pun">]);</span></pre>

<p>
	حيث أن:
</p>

<ul>
<li>
		<strong><code>event</code></strong>: هو اسم الحدث، كـ <code>"click"</code> مثلًا.
	</li>
	<li>
		<strong><code>handler</code></strong>: هي دالّة المعالج.
	</li>
	<li>
		<strong><code>options</code></strong>: هو كائن إضافي اختياري، وله الخاصيّات التالية: <code>once</code>: إذا كانت قيمتها <code>true</code>، فإن منصت الحدث (event listener) يزول تلقائيا بعد حصول الحدث. <code>capture</code> المرحلة التي يُعالَج فيها الحدث، وسنتطرّق إليها لاحقا في مقال <a data-ss1613981987="1" data-ss1613982967="1" href="#" rel="">انتشار اﻷحداث</a>. لأسباب تاريخية، يمكن أن تحمل <code>options</code> القيمة <code>true</code> \ <code>false</code> ويكون لذلك نفس معنى <code>{capture: false/true}</code>. <code>passive</code>: إذا كانت قيمتها <code>true</code>، فلن يستدعي المعالجُ التابعَ <code>preventDefault()‎</code>، وسنشرح ذلك في مقال <a data-ss1613981987="1" data-ss1613982967="1" href="#" rel="">أفعال المتصفّح الافتراضية</a>.
	</li>
</ul>
<p>
	يمكن حذف المعالج بواسطة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8776_40" style="">
<span class="pln">element</span><span class="pun">.</span><span class="pln">removeEventListener</span><span class="pun">(</span><span class="pln">event</span><span class="pun">,</span><span class="pln"> handler</span><span class="pun">,</span><span class="pln"> </span><span class="pun">[</span><span class="pln">options</span><span class="pun">]);</span></pre>

<hr>
<p>
	<strong>تنبيه: يتطلّب الحذفُ الدالةَ نفسَها</strong>
</p>

<p>
	لحذف المعالج يجب تمرير نفس الدالة التي عُيّنت من قبل. فلو جرّبنا مثلًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8776_42" style="">
<span class="pln">elem</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="pln"> </span><span class="str">"click"</span><span class="pln"> </span><span class="pun">,</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> alert</span><span class="pun">(</span><span class="str">'Thanks!'</span><span class="pun">));</span><span class="pln">
</span><span class="com">// ....</span><span class="pln">
elem</span><span class="pun">.</span><span class="pln">removeEventListener</span><span class="pun">(</span><span class="pln"> </span><span class="str">"click"</span><span class="pun">,</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> alert</span><span class="pun">(</span><span class="str">'Thanks!'</span><span class="pun">));</span></pre>

<p>
	لن يحُذف المعالج، لأن <code>removeEventListener</code> قد تلقّى دالة أخرى -- لها نفس الشيفرة، لكن لا يهم ذلك لأنها كائن دالة آخر.
</p>

<p>
	هذه هي الطريقة الصحيحة لحذف المعالج:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8776_44" style="">
<span class="kwd">function</span><span class="pln"> handler</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln"> </span><span class="str">'Thanks!'</span><span class="pln"> </span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

input</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"click"</span><span class="pun">,</span><span class="pln"> handler</span><span class="pun">);</span><span class="pln">
</span><span class="com">// ....</span><span class="pln">
input</span><span class="pun">.</span><span class="pln">removeEventListener</span><span class="pun">(</span><span class="str">"click"</span><span class="pun">,</span><span class="pln"> handler</span><span class="pun">);</span></pre>

<p>
	يرُجى التنبّه هنا إلى أنّه إذا لم نحفظ الدالة في متغيّر، فلا يمكننا حذفها. إذ لا سبيل إلى "إعادة قراءة" المعالجات المُعيّنة بواسطة <code>addEventListener</code>.
</p>

<hr>
<p>
	يمكّن الاستدعاء المتكرّر لـ <code>addEventListener</code> من تعيين عدّة معالجات كالتالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_8776_100" style="">
<span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"elem"</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"button"</span><span class="pln"> </span><span class="atn">value</span><span class="pun">=</span><span class="atv">"Click me"</span><span class="tag">/&gt;</span><span class="pln">

</span><span class="tag">&lt;script&gt;</span><span class="pln">
  </span><span class="kwd">function</span><span class="pln"> handler1</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    alert</span><span class="pun">(</span><span class="str">'Thanks!'</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">};</span><span class="pln">

  </span><span class="kwd">function</span><span class="pln"> handler2</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    alert</span><span class="pun">(</span><span class="str">'Thanks again!'</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  elem</span><span class="pun">.</span><span class="pln">onclick </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> alert</span><span class="pun">(</span><span class="str">"Hello"</span><span class="pun">);</span><span class="pln">
  elem</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"click"</span><span class="pun">,</span><span class="pln"> handler1</span><span class="pun">);</span><span class="pln"> </span><span class="com">// Thanks!</span><span class="pln">
  elem</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"click"</span><span class="pun">,</span><span class="pln"> handler2</span><span class="pun">);</span><span class="pln"> </span><span class="com">// Thanks again!</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" data-ss1613981987="1" data-ss1613982967="1" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-introduction-browser-events-ex6" src="https://codepen.io/Hsoub/embed/MWbEobb?height=265&amp;theme-id=light&amp;default-tab=html,result">See the Pen JS-p2-introduction-browser-events-ex6 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	كما هو مبيّن في المثال أعلاه، يمكن تعيين معالجات باستخدام كلٍّ من خاصيّة DOM و<code>addEventListener</code> معًا، لكن في الغالب تُستخدم إحداهما فقط.
</p>

<hr>
<p>
	<strong>تنبيه: لا يمكن تعيين معالجات لبعض الأحداث إلا بواسطة <code>addEventListener</code></strong>
</p>

<p>
	توجد أحداثٌ لا يمكن تعيين معالجات لها عن طريق خاصيّة DOM ، بل تشترط استخدام <code>addEventListener</code>.
</p>

<p>
	على سبيل المثال، الحدث <code>DOMContentLoaded</code>، الذي يحصل حين الانتهاء من تحميل المستند وبناء DOM.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8776_48" style="">
<span class="com">// لن يتم تنفيذ هذا أبدا</span><span class="pln">
document</span><span class="pun">.</span><span class="pln">onDOMContentLoaded </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  alert</span><span class="pun">(</span><span class="str">"DOM built"</span><span class="pun">);</span><span class="pln">
</span><span class="pun">};</span></pre>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8776_50" style="">
<span class="com">// هذه الطريقة أصحّ</span><span class="pln">
document</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"DOMContentLoaded"</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  alert</span><span class="pun">(</span><span class="str">"DOM built"</span><span class="pun">);</span><span class="pln">
</span><span class="pun">});</span></pre>

<p>
	بذلك يكون<code>addEventListener</code> أشمل، رغم أنّ هذه الأحداث تُعدّ استثناءًا وليست القاعدة.
</p>

<h2>
	كائن الحدث
</h2>

<p>
	لمعالجة الحدث كما ينبغي، قد يلزمنا معرفة المزيد عمّا حصل بالضبط. فليس مجرّد "النقر" أو "الضغط"، بل أيضا ما هي إحداثيات المؤشر؟ أو ما هو الزر التي ضُغط؟ إلى غير ذلك.
</p>

<p>
	عند وقوع حدثٍ ما، يُنشئ المتصفّحُ <em>كائن حدث</em> ويضع فيه التفاصيل، ثم يمرّره على شكل وسيط للمعالج.
</p>

<p>
	هذا مثال لكيفية الحصول على إحداثيات المؤشر من كائن الحدث:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_8776_52" style="">
<span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"button"</span><span class="pln"> </span><span class="atn">value</span><span class="pun">=</span><span class="atv">"Click me"</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"elem"</span><span class="tag">&gt;</span><span class="pln">

</span><span class="tag">&lt;script&gt;</span><span class="pln">
  elem</span><span class="pun">.</span><span class="pln">onclick </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// يظهر نوع الحدث والعنصر وإحداثيات النقر</span><span class="pln">
    alert</span><span class="pun">(</span><span class="pln">event</span><span class="pun">.</span><span class="pln">type </span><span class="pun">+</span><span class="pln"> </span><span class="str">" at "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> event</span><span class="pun">.</span><span class="pln">currentTarget</span><span class="pun">);</span><span class="pln">
    alert</span><span class="pun">(</span><span class="str">"Coordinates: "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> event</span><span class="pun">.</span><span class="pln">clientX </span><span class="pun">+</span><span class="pln"> </span><span class="str">":"</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> event</span><span class="pun">.</span><span class="pln">clientY</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">};</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" data-ss1613981987="1" data-ss1613982967="1" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-introduction-browser-events-ex7" src="https://codepen.io/Hsoub/embed/ZEBXyBL?height=265&amp;theme-id=light&amp;default-tab=html,result">See the Pen JS-p2-introduction-browser-events-ex7 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	هذه بعض خاصيّات كائن الحدث <code>event</code>:
</p>

<ul>
<li>
		<p>
			<strong><code>event.type</code></strong>: نوع الحدث، و هو في هذا المثال <code>"click"</code>
		</p>
	</li>
	<li>
		<p>
			<strong><code>event.currentTarget</code></strong>: العنصر الذي عالج الحدث. وهو نفس <code>this</code>، إلا إذا كان المعالج دالة سهمية أو أن <code>this</code> الخاصّ به مرتبط (bound) بشيء آخر، فعندها يمكن الحصول على العنصر بواسطة <code>event.currentTarget</code>.
		</p>
	</li>
	<li>
		<p>
			<strong><code>event.clientX / event.clientY</code></strong>: هي إحداثيات المؤشّر بالنسبة للنافذة، عند الأحداث المتعلقة بالمؤشّر.
		</p>
	</li>
</ul>
<p>
	هناك المزيد من الخاصيّات، والكثير منها متعلق بنوع الحدث. فأحداث لوحة المفاتيح لها مجموعة من الخاصيّات، وأحداث المؤشر لها مجموعة أخرى. سندرس ذلك لاحقا عندما نتطرّق لمختلف الأحداث بالتفصيل.
</p>

<hr>
<p>
	<strong>ملاحظة: كائن الحدث متوفر أيضا للمعالجات في HTML</strong>
</p>

<p>
	إذا عينّا معالجًا في HTML، فإنّه من الممكن أيضا استخدام الكائن <code>event</code>، كالتالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_8776_54" style="">
<span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"button"</span><span class="pln"> </span><span class="atn">onclick</span><span class="pun">=</span><span class="atv">"</span><span class="pln">alert</span><span class="pun">(</span><span class="pln">event</span><span class="pun">.</span><span class="pln">type</span><span class="pun">)</span><span class="atv">"</span><span class="pln"> </span><span class="atn">value</span><span class="pun">=</span><span class="atv">"Event type"</span><span class="tag">&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" data-ss1613981987="1" data-ss1613982967="1" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-introduction-browser-events-ex8" src="https://codepen.io/Hsoub/embed/rNWGwWm?height=265&amp;theme-id=light&amp;default-tab=result">See the Pen JS-p2-introduction-browser-events-ex8 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	يمكننا ذلك لأن المتصفّح حينما يقرأ السمة، فإنّه ينشئ معالجًا بهذا الشكل: <code>function(event) { alert(event.type) }</code>‎، فيكون اسم وسيطه الأول <code>"event"</code>، ومحتواه مأخوذا من السمة.
</p>

<hr>
<h2>
	الكائنات المعالجة: handleEvent
</h2>

<p>
	يمكن بواسطة <code>addEventListener</code> تعيين معالجٍ على شكل كائن أيضا، وعند وقوع الحدث، يُستدعى التابع <code>handleEvent</code>. على سبيل المثال:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_8776_56" style="">
<span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"elem"</span><span class="tag">&gt;</span><span class="pln">Click me</span><span class="tag">&lt;/button&gt;</span><span class="pln">

</span><span class="tag">&lt;script&gt;</span><span class="pln">
  let obj </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    handleEvent</span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      alert</span><span class="pun">(</span><span class="pln">event</span><span class="pun">.</span><span class="pln">type </span><span class="pun">+</span><span class="pln"> </span><span class="str">" at "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> event</span><span class="pun">.</span><span class="pln">currentTarget</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">};</span><span class="pln">

  elem</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">'click'</span><span class="pun">,</span><span class="pln"> obj</span><span class="pun">);</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" data-ss1613981987="1" data-ss1613982967="1" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-introduction-browser-events-ex8" src="https://codepen.io/Hsoub/embed/rNWGwWm?height=265&amp;theme-id=light&amp;default-tab=result">See the Pen JS-p2-introduction-browser-events-ex8 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	كما نرى، عندما يستقبل <code>addEventListener</code> كائنًا، فإنه يستدعي <code>obj.handleEvent(event)‎</code> في حال وقوع الحدث.
</p>

<p>
	يمكننا أيضا استخدام صنفٍ لذلك:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_8776_58" style="">
<span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"elem"</span><span class="tag">&gt;</span><span class="pln">Click me</span><span class="tag">&lt;/button&gt;</span><span class="pln">

</span><span class="tag">&lt;script&gt;</span><span class="pln">
  </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Menu</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    handleEvent</span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="kwd">switch</span><span class="pun">(</span><span class="pln">event</span><span class="pun">.</span><span class="pln">type</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">case</span><span class="pln"> </span><span class="str">'mousedown'</span><span class="pun">:</span><span class="pln">
          elem</span><span class="pun">.</span><span class="pln">innerHTML </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Mouse button pressed"</span><span class="pun">;</span><span class="pln">
          </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">case</span><span class="pln"> </span><span class="str">'mouseup'</span><span class="pun">:</span><span class="pln">
          elem</span><span class="pun">.</span><span class="pln">innerHTML </span><span class="pun">+=</span><span class="pln"> </span><span class="str">"...and released."</span><span class="pun">;</span><span class="pln">
          </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">
      </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  let menu </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Menu</span><span class="pun">();</span><span class="pln">
  elem</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">'mousedown'</span><span class="pun">,</span><span class="pln"> menu</span><span class="pun">);</span><span class="pln">
  elem</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">'mouseup'</span><span class="pun">,</span><span class="pln"> menu</span><span class="pun">);</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" data-ss1613981987="1" data-ss1613982967="1" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-introduction-browser-events-ex9" src="https://codepen.io/Hsoub/embed/ExNwXZw?height=265&amp;theme-id=light&amp;default-tab=html,result">See the Pen JS-p2-introduction-browser-events-ex9 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	يقوم نفس الكائن هنا بمعالجة كلا الحدثين. لكن ينبغي التنبه إلى أنه يجب تحديد الأحداث المراد الإنصات إليها باستخدام <code>addEventListener</code> صراحةً. يتلقى الكائن <code>menu</code> هنا الحدثين <code>mousedown</code> و <code>mouseup</code> دون غيرهما من أنواع الأحداث الأخرى.
</p>

<p>
	لا يلزم التابع <code>handleEvent</code> أن يقوم بكامل العمل، بل يمكنه استدعاء توابع أخرى مختصة بأحداث معيّنة، كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_8776_60" style="">
<span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"elem"</span><span class="tag">&gt;</span><span class="pln">Click me</span><span class="tag">&lt;/button&gt;</span><span class="pln">

</span><span class="tag">&lt;script&gt;</span><span class="pln">
  </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Menu</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    handleEvent</span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="com">// mousedown -&gt; onMousedown</span><span class="pln">
      let method </span><span class="pun">=</span><span class="pln"> </span><span class="str">'on'</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> event</span><span class="pun">.</span><span class="pln">type</span><span class="pun">[</span><span class="lit">0</span><span class="pun">].</span><span class="pln">toUpperCase</span><span class="pun">()</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> event</span><span class="pun">.</span><span class="pln">type</span><span class="pun">.</span><span class="pln">slice</span><span class="pun">(</span><span class="lit">1</span><span class="pun">);</span><span class="pln">
      </span><span class="kwd">this</span><span class="pun">[</span><span class="pln">method</span><span class="pun">](</span><span class="pln">event</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    onMousedown</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      elem</span><span class="pun">.</span><span class="pln">innerHTML </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Mouse button pressed"</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    onMouseup</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      elem</span><span class="pun">.</span><span class="pln">innerHTML </span><span class="pun">+=</span><span class="pln"> </span><span class="str">"...and released."</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  let menu </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Menu</span><span class="pun">();</span><span class="pln">
  elem</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">'mousedown'</span><span class="pun">,</span><span class="pln"> menu</span><span class="pun">);</span><span class="pln">
  elem</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">'mouseup'</span><span class="pun">,</span><span class="pln"> menu</span><span class="pun">);</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" data-ss1613981987="1" data-ss1613982967="1" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-introduction-browser-events-ex10" src="https://codepen.io/Hsoub/embed/JjbrJEp?height=265&amp;theme-id=light&amp;default-tab=result">See the Pen JS-p2-introduction-browser-events-ex10 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	هكذا يتم فصل المعالجات على حدة، مما قد يجعل دعمها أسهل.
</p>

<h2>
	الملخص
</h2>

<p>
	توجد ثلاث طرق لتعيين معالجات للأحداث:
</p>

<ol>
<li>
		سمة HTML: ‏ <code>onclick="..."</code>‎.
	</li>
	<li>
		خاصيّة DOM:‏ <code>elem.onclick = function</code>.
	</li>
	<li>
		توابع: <code>elem.addEventListener(event, handler[, phase])</code>‎ للإضافة، و <code>removeEventListener</code> للحذف.
	</li>
</ol>
<p>
	يندر استخدام سمات HTML، لأن جافاسكربت تبدو غريبة وسط وسم HTML. بالإضافة إلى أنه لا يمكن كتابة الكثير من الشيفرة هناك.
</p>

<p>
	لا بأس باستخدام خاصيّات DOM، غير أنه لا يمكن تعيين أكثر من معالج لنفس الحدث. في الكثير من الأحيان قد لا يمثّل هذا القيد مشكلة تُذكر.
</p>

<p>
	تُعدّ الطريقة الأخيرة أكثرها مرونة، لكنها أيضا أطولها كتابة. هناك بعض الأحداث التي لا تعمل إلا بواسطتها، على سبيل المثال <code>transitionend</code> و <code>DOMContentLoaded</code> (ستُدرس لاحقًا). بالإضافة إلى ذلك، تدعم <code>addEventListener</code> تعيين معالجات للأحداث على شكل كائنات، ويُستدعى حينها التابع <code>handleEvent</code> عند وقوع الحدث.
</p>

<p>
	أيّا كانت طريقة تعيين المعالج، فإنّه يستقبل كائن حدث كوسيط أول. يحتوي هذا الكائن تفاصيل ما قد حصل.
</p>

<p>
	سنتعلم المزيد عن الأحداث عموما، وعن مختلف أنواع الأحداث في المقالات القادمة.
</p>

<h2>
	التمارين
</h2>

<h3>
	الإخفاء عند النقر
</h3>

<p>
	الأهمية: 5
</p>

<p>
	أضف جافاسكربت إلى الزر <code>button</code> لجعل <code>&lt;div id="text"‎&gt;</code> يختفي عند النقر عليه، <a data-ss1613981987="1" data-ss1613982967="1" href="https://en.js.cx/task/hide-other/solution/" rel="external nofollow">كما هنا</a>
</p>

<p>
	<a data-ss1613981987="1" data-ss1613982967="1" href="https://plnkr.co/edit/6vWtOzQrn7qGGuey?p=preview" rel="external nofollow">افتح البيئة التجريبيّة لإنجاز التمرين</a>
</p>

<h3>
	الحل
</h3>

<p>
	<a data-ss1613981987="1" data-ss1613982967="1" href="https://plnkr.co/edit/XYTLqWVjKhbaXILs?p=preview" rel="external nofollow">افتح البيئة التجريبيّة لمشاهدة الحلّ</a>
</p>

<h3>
	الاختفاء عند النقر
</h3>

<p>
	الأهمية: 5
</p>

<p>
	أنشئ زرّا يخفي نفسه عند النقر عليه.
</p>

<h3>
	الحل
</h3>

<p>
	يمكن استخدام <code>this</code> للإشارة إلى "العنصر نفسه" هنا:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_8776_62" style="">
<span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"button"</span><span class="pln"> </span><span class="atn">onclick</span><span class="pun">=</span><span class="atv">"</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">hidden</span><span class="pun">=</span><span class="kwd">true</span><span class="atv">"</span><span class="pln"> </span><span class="atn">value</span><span class="pun">=</span><span class="atv">"Click to hide"</span><span class="tag">&gt;</span></pre>

<h3>
	أيّ المعالجات ستُنفّذ؟
</h3>

<p>
	اﻷهمية: 5
</p>

<p>
	يحتوي المتغير <code>button</code> على زرّ، وليس عليه معالجات.
</p>

<p>
	أيّ من المعالجات ستُنفّذ بعد تشغيل الشيفرة أدناه؟ ما هي التنبيهات التي تظهر؟
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8776_64" style="">
<span class="pln">button</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"click"</span><span class="pun">,</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> alert</span><span class="pun">(</span><span class="str">"1"</span><span class="pun">));</span><span class="pln">

button</span><span class="pun">.</span><span class="pln">removeEventListener</span><span class="pun">(</span><span class="str">"click"</span><span class="pun">,</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> alert</span><span class="pun">(</span><span class="str">"1"</span><span class="pun">));</span><span class="pln">

button</span><span class="pun">.</span><span class="pln">onclick </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> alert</span><span class="pun">(</span><span class="lit">2</span><span class="pun">);</span></pre>

<h3>
	الحل
</h3>

<p>
	الجواب هو <code>1</code> و <code>2</code>.
</p>

<p>
	يستجيب المعالج الأول لأنه لم يُحذف بواسطة <code>removeEventListener</code>. لحذف المعالج، يجب تمرير نفس الدالة التي عُيّنت بالضبط. وفي الكود أعلاه، مُررت دالة جديدة، تبدو مثلها تماما لكنها تبقى دالة أخرى.
</p>

<p>
	لحذف كائن دالة، نحتاج أن نحفظ مرجعا لها، كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8776_66" style="">
<span class="kwd">function</span><span class="pln"> handler</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
 alert</span><span class="pun">(</span><span class="lit">1</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

button</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"click"</span><span class="pun">,</span><span class="pln"> handler</span><span class="pun">);</span><span class="pln">
button</span><span class="pun">.</span><span class="pln">removeEventListener</span><span class="pun">(</span><span class="str">"click"</span><span class="pun">,</span><span class="pln"> handler</span><span class="pun">);</span></pre>

<p>
	أما المعالج <code>button.onclick</code> فهو يعمل بشكل مستقل وبالإضافة إلى <code>addEventListener</code>.
</p>

<h3>
	حرّك الكرة في الملعب
</h3>

<p>
	حرّك الكرة في الملعب بواسطة النقر، <a data-ss1613981987="1" data-ss1613982967="1" href="https://en.js.cx/task/move-ball-field/solution/" rel="external nofollow">كما هنا</a>
</p>

<p>
	المطلوب:
</p>

<ul>
<li>
		يجب أن ينتقل مركز الكرة إلى موضع المؤشر عند النقر (حبذا دون الخروج عن حافة الملعب).
	</li>
	<li>
		تحريكات CSS مُرحّب بها.
	</li>
	<li>
		يجب ألا تخرج الكرة عن حدود الملعب.
	</li>
	<li>
		يجب ألا يؤدي تمرير الصفحة إلى اختلاط الأمور .
	</li>
</ul>
<p>
	ملاحظات:
</p>

<ul>
<li>
		يجب أن تشتغل الشيفرة مع مختلف أحجام الكرة والملعب، وألا تكون مرتبطة بقيم معينة.
	</li>
	<li>
		استخدم الخاصيّات <code>event.clientX/event.clientY</code> للحصول على إحداثيات النقر.
	</li>
</ul>
<p>
	<a data-ss1613981987="1" data-ss1613982967="1" href="https://plnkr.co/edit/yi6xXY3XkYDiZbeD?p=preview" rel="external nofollow">افتح البيئة التجريبيّة لإنجاز التمرين</a>
</p>

<h3>
	الحل
</h3>

<p>
	أولا، علينا أن نختار طريقة لتغيير موضع الكرة.
</p>

<p>
	لا يمكننا استخدام <code>position:fixed</code> لذلك، لأن تمرير الصفحة قد يخرج الكرة عن الملعب.
</p>

<p>
	لذا يلزمنا استخدام <code>position:absolute</code>، ولكي يكون التموضع جيد الإحكام، علينا أن نعطي للملعب نفسه وضعية، لتكون بذلك الكرة مُموضَعة بالنسبة إلى الملعب:
</p>

<pre class="ipsCode prettyprint lang-css prettyprinted" id="ips_uid_8776_68" style="">
<span class="com">#field {</span><span class="pln">
  width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">200px</span><span class="pun">;</span><span class="pln">
  height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">150px</span><span class="pun">;</span><span class="pln">
  position</span><span class="pun">:</span><span class="pln"> relative</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="com">#ball {</span><span class="pln">
  position</span><span class="pun">:</span><span class="pln"> absolute</span><span class="pun">;</span><span class="pln">
  left</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> </span><span class="com">/* (بالنسبة إلى أقرب سلف مموضَع (الملعب */</span><span class="pln">
  top</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
  transition</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1s</span><span class="pln"> all</span><span class="pun">;</span><span class="pln"> </span><span class="com">/* الكرة تطير leftو top المتعلقة بـ CSS تجعل تحريكات */</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	بعدها، علينا أن نعطي القيم المناسبة لـ <code>ball.style.left/top</code> ، إذ هي الآن تمثل إحداثيات الكرة بالنسبة إلى الملعب.
</p>

<p>
	هذه هي الصورة:
</p>

<p style="text-align: center;">
	<img alt="move-ball-coords.png" class="ipsImage ipsImage_thumbnailed" data-fileid="58074" data-unique="o5sslampa" src="https://academy.hsoub.com/uploads/monthly_2021_02/move-ball-coords.png.5311e68cc4d2c1ebe9e65521bfc6fad8.png"></p>

<p>
	تمثل <code>event.clientX/clientY</code> إحداثيات موضع النقر بالنسبة إلى النافذة.
</p>

<p>
	للحصول على الإحداثية <code>left</code> لموضع النقر بالنسبة إلى الملعب، يمكننا أن نطرح كلّا من الحافة اليسرى الملعب وسمك الحد:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8776_70" style="">
<span class="pln">let left </span><span class="pun">=</span><span class="pln"> event</span><span class="pun">.</span><span class="pln">clientX </span><span class="pun">-</span><span class="pln"> fieldCoords</span><span class="pun">.</span><span class="pln">left </span><span class="pun">-</span><span class="pln"> field</span><span class="pun">.</span><span class="pln">clientLeft</span><span class="pun">;</span></pre>

<p>
	عادةً، يشير <code>ball.style.left</code> إلى "الحافة اليسرى للعنصر" (الكرة)، فإذا أعطيناه قيمة المتغير <code>left</code>، فإن حافة الكرة هي التي ستكون تحت المؤشر وليس مركزها.
</p>

<p>
	علينا إذًا أن نزيح الكرة بمقدار نصف عرضها إلى اليسار، وبمقدار نصف طولها إلى الأعلى كي نجعلها في المنتصف.
</p>

<p>
	فتكون القيمة النهائية لـ <code>left</code> هي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8776_72" style="">
<span class="pln">let left </span><span class="pun">=</span><span class="pln"> event</span><span class="pun">.</span><span class="pln">clientX </span><span class="pun">-</span><span class="pln"> fieldCoords</span><span class="pun">.</span><span class="pln">left </span><span class="pun">-</span><span class="pln"> field</span><span class="pun">.</span><span class="pln">clientLeft </span><span class="pun">-</span><span class="pln"> ball</span><span class="pun">.</span><span class="pln">offsetWidth</span><span class="pun">/</span><span class="lit">2</span><span class="pun">;</span></pre>

<p>
	تُحسب الإحداثية العمودية بنفس الطريقة.
</p>

<p>
	يُرجى التنبه إلى أنه يجب أن يكون عرض الكرة وطولها معلومين عند قراءة <code>ball.offsetWidth</code>. يجب أن يُحدد ذلك في HTML أو CSS.
</p>

<p>
	<a data-ss1613981987="1" data-ss1613982967="1" href="https://plnkr.co/edit/8dwHzsyytfPDr08F?p=preview" rel="external nofollow">افتح البيئة التجريبيّة لمشاهدة الحلّ</a>
</p>

<h3>
	أنشئ قائمة منحدرة
</h3>

<p>
	اﻷهمية: 5
</p>

<p>
	أنشئ قائمة تُفتح وتُغلق عند النقر <a data-ss1613981987="1" data-ss1613982967="1" href="https://en.js.cx/task/sliding-menu/solution/" rel="external nofollow">كما هنا</a>
</p>

<p>
	ملاحظة: ينبغي التعديل على الملف المصدري لـ HTML/CSS.
</p>

<p>
	<a data-ss1613981987="1" data-ss1613982967="1" href="https://plnkr.co/edit/sDzWgqYxeNrla3Kz?p=preview&amp;preview" rel="external nofollow">افتح البيئة التجريبيّة لإنجاز التمرين</a>
</p>

<h3>
	الحل
</h3>

<p>
	<strong>HTML/CSS</strong>
</p>

<p>
	لننشئ أولا HTML/CSS.
</p>

<p>
	تُعدّ القائمة مُكوّنا رسوميا مستقلا بذاته في الصفحة، لذا فيفضّل وضعها في عنصر DOM واحد.
</p>

<p>
	يمكن تنسيق عناصر القائمة على شكل <code>ul/li</code>.
</p>

<p>
	هذا مثال عن البنية:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_8776_74" style="">
<span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"menu"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"title"</span><span class="tag">&gt;</span><span class="pln">Sweeties (click me)!</span><span class="tag">&lt;/span&gt;</span><span class="pln">
  </span><span class="tag">&lt;ul&gt;</span><span class="pln">
    </span><span class="tag">&lt;li&gt;</span><span class="pln">Cake</span><span class="tag">&lt;/li&gt;</span><span class="pln">
    </span><span class="tag">&lt;li&gt;</span><span class="pln">Donut</span><span class="tag">&lt;/li&gt;</span><span class="pln">
    </span><span class="tag">&lt;li&gt;</span><span class="pln">Honey</span><span class="tag">&lt;/li&gt;</span><span class="pln">
  </span><span class="tag">&lt;/ul&gt;</span><span class="pln">
</span><span class="tag">&lt;/div&gt;</span></pre>

<p>
	استخدمنا <code>&lt;span&gt;</code> للعنوان، لأن <code>&lt;div&gt;</code> له ضمنيّا الخاصيّة <code>display:block</code> ، مما سيجعله يحتل 100% من المساحة الأفقية، هكذا:
</p>

<pre class="ipsCode">
&lt;div style="border: solid red 1px" onclick="alert(1)"&gt;Sweeties (click me)!&lt;/div&gt;
</pre>

<p style="text-align: center;">
	<img alt="div.png" class="ipsImage ipsImage_thumbnailed" data-fileid="58073" data-unique="pp4e6pf9t" src="https://academy.hsoub.com/uploads/monthly_2021_02/div.png.243a17ceb70615001566b9b86b847022.png"></p>

<p>
	فإذا وضعنا عليه <code>onclick</code> ، فإنه سيستجيب للنقرات التي على يمين النص أيضا.
</p>

<p>
	وبما أن <code>&lt;span&gt;</code> له ضمنيّا الخاصيّة <code>display: inline</code>، فإنه سيحتل من المساحة فقط ما يكفي لاحتواء النص:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_8776_76" style="">
<span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">style</span><span class="pun">=</span><span class="atv">"</span><span class="pln">border</span><span class="pun">:</span><span class="pln"> solid red </span><span class="lit">1px</span><span class="atv">"</span><span class="pln"> </span><span class="atn">onclick</span><span class="pun">=</span><span class="atv">"</span><span class="pln">alert</span><span class="pun">(</span><span class="lit">1</span><span class="pun">)</span><span class="atv">"</span><span class="tag">&gt;</span><span class="pln">Sweeties (click me)!</span><span class="tag">&lt;/span&gt;</span></pre>

<p style="text-align: center;">
	<img alt="span.png" class="ipsImage ipsImage_thumbnailed" data-fileid="58075" data-unique="zarq8j37h" src="https://academy.hsoub.com/uploads/monthly_2021_02/span.png.452a9238c3995fe1208e1333fa61d32b.png"></p>

<p>
	<strong>إقلاب القائمة</strong>
</p>

<p>
	يؤدي إقلاب (toggling) القائمة إلى تغيير السهم وإظهار أو إخفاء عناصرها.
</p>

<p>
	يمكن القيام بكل هذه التغيرات من خلال CSS. في جافاسكربت علينا فقط تمييز الوضع الحالي للقائمة من خلال إضافة أو إزالة الصنف <code>open.</code>.
</p>

<p>
	بدون <code>open.</code> تكون القائمة منقبضة:
</p>

<pre class="ipsCode prettyprint lang-css prettyprinted" id="ips_uid_8776_78" style="">
<span class="pun">.</span><span class="pln">menu ul </span><span class="pun">{</span><span class="pln">
  margin</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
  list</span><span class="pun">-</span><span class="pln">style</span><span class="pun">:</span><span class="pln"> none</span><span class="pun">;</span><span class="pln">
  padding</span><span class="pun">-</span><span class="pln">left</span><span class="pun">:</span><span class="pln"> </span><span class="lit">20px</span><span class="pun">;</span><span class="pln">
  display</span><span class="pun">:</span><span class="pln"> none</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="pun">.</span><span class="pln">menu </span><span class="pun">.</span><span class="pln">title</span><span class="pun">::</span><span class="pln">before </span><span class="pun">{</span><span class="pln">
  content</span><span class="pun">:</span><span class="pln"> </span><span class="str">'▶ '</span><span class="pun">;</span><span class="pln">
  font</span><span class="pun">-</span><span class="pln">size</span><span class="pun">:</span><span class="pln"> </span><span class="lit">80</span><span class="pun">%;</span><span class="pln">
  color</span><span class="pun">:</span><span class="pln"> green</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	… ومع وجوده يتغير السهم وتظهر عناصر القائمة:
</p>

<pre class="ipsCode prettyprint lang-css prettyprinted" id="ips_uid_8776_80" style="">
<span class="pun">.</span><span class="pln">menu</span><span class="pun">.</span><span class="pln">open </span><span class="pun">.</span><span class="pln">title</span><span class="pun">::</span><span class="pln">before </span><span class="pun">{</span><span class="pln">
  content</span><span class="pun">:</span><span class="pln"> </span><span class="str">'▼ '</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="pun">.</span><span class="pln">menu</span><span class="pun">.</span><span class="pln">open ul </span><span class="pun">{</span><span class="pln">
  display</span><span class="pun">:</span><span class="pln"> block</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	<a data-ss1613981987="1" data-ss1613982967="1" href="https://plnkr.co/edit/bO5pDSqsI4AbQzbL?p=preview" rel="external nofollow">افتح البيئة التجريبيّة لمشاهدة الحلّ</a>
</p>

<h3>
	أضف زرّا للإغلاق
</h3>

<p>
	اﻷهمية: 5
</p>

<p>
	هناك مجموعة من الرسائل.
</p>

<p>
	باستخدام جافاسكربت، أضف زرا في أقصى اليمين العلوي للرسائل لإغلاقها.
</p>

<p>
	يجب أن تبدو النتيجة <a data-ss1613981987="1" data-ss1613982967="1" href="https://en.js.cx/task/hide-message/solution/" rel="external nofollow">كما هنا</a>.
</p>

<p>
	<a data-ss1613981987="1" data-ss1613982967="1" href="https://plnkr.co/edit/bIotBX876EI3kDzy?p=preview&amp;preview" rel="external nofollow">افتح البيئة التجريبيّة لإنجاز التمرين</a>
</p>

<h3>
	الحل
</h3>

<p>
	لإضافة الزر، يمكن استخدام كلّ من <code>position:absolute</code> (وجعل وضعية اللوحة نسبية <code>position:relative</code>) أو <code>float:right</code>. تتميز طريقة <code>float:right</code> بأنها تضمن عدم تقاطع الزر مع النص، لكن <code>position:absolute</code> تمنح المزيد من الحرية. فالخيار لك.
</p>

<p>
	بذلك تكون الشيفرة لكل من الألواح كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8776_82" style="">
<span class="pln">pane</span><span class="pun">.</span><span class="pln">insertAdjacentHTML</span><span class="pun">(</span><span class="str">"afterbegin"</span><span class="pun">,</span><span class="pln"> </span><span class="str">'&lt;button class="remove-button"&gt;[x]&lt;/button&gt;'</span><span class="pun">);</span></pre>

<p>
	و يصير <code>&lt;button&gt;</code> بذلك <code>pane.firstChild</code>، مما يمكّننا من تعيين معالج له هكذا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8776_84" style="">
<span class="pln">pane</span><span class="pun">.</span><span class="pln">firstChild</span><span class="pun">.</span><span class="pln">onclick </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> pane</span><span class="pun">.</span><span class="pln">remove</span><span class="pun">();</span></pre>

<p>
	<a data-ss1613981987="1" data-ss1613982967="1" href="https://plnkr.co/edit/anSCWBqFUzLiAok5?p=preview&amp;preview" rel="external nofollow">افتح البيئة التجريبيّة لمشاهدة الحلّ</a>
</p>

<h3>
	الدوّار
</h3>

<p>
	اﻷهمية: 4
</p>

<p>
	أنجز دوّارا -- شريط من الصور يمكن تمريره بواسطة أسهم، <a data-ss1613981987="1" data-ss1613982967="1" href="https://en.js.cx/task/carousel/solution/" rel="external nofollow">كما هنا</a>
</p>

<p>
	يمكننا لاحقا إضافة المزيد من المزايا كالتمرير اللامتناهي، والتحميل الديناميكي وغير ذلك.
</p>

<p>
	ملاحظة:
</p>

<p>
	في هذا التمرين، تُمثل بنية HTML/CSS في الحقيقة 90% من الحل.
</p>

<p>
	<a data-ss1613981987="1" data-ss1613982967="1" href="https://plnkr.co/edit/qP4TJJCtiSTJf6Zi?p=preview" rel="external nofollow">افتح البيئة التجريبيّة لإنجاز التمرين</a>
</p>

<h3>
	الحل
</h3>

<p>
	يمكن تمثيل شريط الصور بقائمة <code>ul/li</code> من الصور <code>&lt;img&gt;</code>.
</p>

<p>
	من المفترض أن هذا الشريط واسع، لكننا نحدّه بـ <code>&lt;div&gt;</code> ثابت الحجم لقطعه، فيبدو بذلك جزء من الشريط فقط:
</p>

<p style="text-align: center;">
	<img alt="carousel1.png" class="ipsImage ipsImage_thumbnailed" data-fileid="58071" data-unique="x1yln5jmx" src="https://academy.hsoub.com/uploads/monthly_2021_02/carousel1.png.377f43a11b5fb4dcc65a7fda76500826.png"></p>

<p>
	لعرض القائمة أفقيا، يجب تطبيق الخاصيّات المناسبة لـ <code>&lt;li&gt;</code> في CSS، مثل <code>display: inline-block</code>.
</p>

<p>
	بالنسبة لـ <code>&lt;img&gt;</code> يجب أيضا تعديل <code>display</code>، لأنها تكون افتراضيا <code>inline</code>. توجد هناك مساحة تحت العناصر <code>inline</code> مخصصة لأذيال الحروف، فيمكن استخدام <code>display:block</code> لإزالتها.
</p>

<p>
	للقيام بالتمرير يمكن إزاحة <code>&lt;ul&gt;</code>. هناك عدة طرق لفعل ذلك، مثل تغيير <code>margin-left</code> أو (لأداء أفضل) استخدام <code>translateX()‎</code>:
</p>

<p style="text-align: center;">
	<img alt="carousel2.png" class="ipsImage ipsImage_thumbnailed" data-fileid="58072" data-unique="pjkb2a5j7" src="https://academy.hsoub.com/uploads/monthly_2021_02/carousel2.png.0e9144ab470ed28b84ffad182445bb19.png"></p>

<p>
	بما أن العرض الخارجي لـ <code>&lt;div&gt;</code> محدود، فإن الصور "الزائدة" ستُخفى.
</p>

<p>
	يُعد الدوّار بأكمله مكونا "رسوميا" مستقلا بذاته، فيُفضل وضعه في <code>&lt;div class="carousel"&gt;</code> واحد وتنسيق جميع الأمور بداخله.
</p>

<p>
	<a data-ss1613981987="1" data-ss1613982967="1" href="https://plnkr.co/edit/U6VSlPwWpUfHzlRB?p=preview" rel="external nofollow">افتح البيئة التجريبيّة لمشاهدة الحلّ</a>
</p>

<p>
	ترجمة -وبتصرف- للمقال <a data-ss1613981987="1" data-ss1613982967="1" href="https://javascript.info/introduction-browser-events" rel="external nofollow">Introduction to browser events</a> من سلسلة <a data-ss1613981987="1" data-ss1613982967="1" href="https://javascript.info/ui" rel="external nofollow">Browser: Document, Events, Interfaces</a> لصاحبها Ilya Kantor
</p>
]]></description><guid isPermaLink="false">1140</guid><pubDate>Mon, 15 Feb 2021 13:00:00 +0000</pubDate></item><item><title>&#x641;&#x647;&#x645; &#x62C;&#x645;&#x644;&#x629; &#x625;&#x62D;&#x62F;&#x627;&#x62B;&#x64A;&#x627;&#x62A; &#x639;&#x646;&#x627;&#x635;&#x631; &#x635;&#x641;&#x62D;&#x629; &#x627;&#x644;&#x648;&#x64A;&#x628; &#x648;&#x636;&#x628;&#x637;&#x647;&#x627; &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A;</title><link>https://academy.hsoub.com/programming/javascript/%D9%81%D9%87%D9%85-%D8%AC%D9%85%D9%84%D8%A9-%D8%A5%D8%AD%D8%AF%D8%A7%D8%AB%D9%8A%D8%A7%D8%AA-%D8%B9%D9%86%D8%A7%D8%B5%D8%B1-%D8%B5%D9%81%D8%AD%D8%A9-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D9%88%D8%B6%D8%A8%D8%B7%D9%87%D8%A7-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r1121/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_01/60140b0dd0657_---(-)----.png.36faea2db50b700fd2036f26ce9fc5ed.png" /></p>

<p>
	يتطلّب تحريك العناصر داخل الصفحة معرفة إحداثياتها. وتعمل معظم الدوالّ في لغة جافاسكربت وفق أحد نظامي الإحداثيات التاليين:
</p>

<ol>
<li>
		إحداثيات بالنسبة للنافذة: تشبه الموضع الثابت (<code>position:fixed</code>)، حيث تُحسب الإحداثيات إنطلاقًا من الركن العلوي الأيسر للنافذة. نسمي هذه الإحداثيات <code>clientX</code> و<code>clientY</code>، وسنوضح السبب من وراء ذلك فيما بعد عند التطرق لخاصيات الأحداث (<code>event properties</code>).
	</li>
	<li>
		إحداثيات بالنسبة للصفحة: تشبه الموضع المطلق (<code>position:absolute</code>)، حيث تُحسب الإحداثيات إنطلاقًا من الركن العلوي الأيسر للصفحة. نسمي هذه الإحداثيات <code>pageX</code> و<code>pageY</code>.
	</li>
</ol>
<p>
	عندما يكون أعلى الصفحة ظاهرًا في النافذة، يكون الركن العلوي الأيسر للصفحة متطابقا مع الركن العلوي الأيسر للنافذة، وتكون الإحداثيات أيضًا متساوية. ولكن بعد تحريك الصفحة تتغيّر إحداثيات العناصر بالنسبة للنافذة كلما تحركت العناصر ضمن النافذة. أما الإحداثيات بالنسبة للصفحة فلا تتغيّر، بل تبقى دائمًا ثابتة.
</p>

<p>
	نأخذ في هذه الصورة نقطة من الصفحة لإظهار إحداثياتها قبل التمرير (الصورة على اليسار) وبعد التمرير (الصورة على اليمين).
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="56633" href="https://academy.hsoub.com/uploads/monthly_2021_01/001coordinates.png.7114918bc9cceca12058d0852b908d73.png" rel=""><img alt="001coordinates.png" class="ipsImage ipsImage_thumbnailed" data-fileid="56633" data-unique="q5yn3urg3" src="https://academy.hsoub.com/uploads/monthly_2021_01/001coordinates.png.7114918bc9cceca12058d0852b908d73.png"></a>
</p>

<p>
	عند تمرير الصفحة:
</p>

<ul>
<li>
		بقيت الترتيبة <code>pageY</code> بالنسبة للصفحة على حالها ولم تتغير، حيث تُحسب إنطلاقًا من أعلى الصفحة (الذي لم يعد ظاهرًا في النافذة بعد التحريك).
	</li>
	<li>
		تغيّرت الترتيبة <code>clientY</code> بالنسبة للنافذة (أصبح السهم أقصر) لأن النقطة نفسها أصبحت أقرب لأعلى النافذة.
	</li>
</ul>
<h2>
	إحداثيات عنصر ما: getBoundingClientRect
</h2>

<p>
	تعيد الدالّة <code>elem.getBoundingClientRect()</code> الإحداثيات (بالنسبة للنافذة) الخاصة بأصغر مستطيل يكون العنصر <code>elem</code> محصورًا فيه بصفته كائنا من الصنف المدمج <a href="https://www.w3.org/TR/geometry-1/#domrect" rel="external nofollow">DOMRect</a>
</p>

<p>
	أهم خاصيات الصنف <code>DOMRect</code>:
</p>

<ul>
<li>
		<code>x</code> و<code>y</code>: إحداثيات نقطة بداية المستطيل بالنسبة للنافذة (X وY).
	</li>
	<li>
		<code>width</code> و<code>height</code>: عرض وطول المستطيل (يمكن أن تكون القيم سالبة).
	</li>
</ul>
<p>
	كما يملك الصنف <code>DOMRect</code> خاصيات مشتقة:
</p>

<ul>
<li>
		<code>top</code> و<code>bottom</code>: ترتيبتي ركني المستطيل العلوي والسفلي.
	</li>
	<li>
		<code>left و</code>right<code>: فاصلتي ركني المستطيل الأيسر والأيمن. فعلى سبيل المثال، عند استعمال الدالّة</code>button.getBoundingClientRect()‎<code>للحصول على إحداثيات زرٍ ما مع تمرير الصفحة نزولًا وصعودًا، ستلاحظ أنه كلما تغيّر موضع الزر بالنسبة للنافذة تغيّرت إحداثياته بالنسبة للنافذة (</code>y<code>و</code>top<code>و</code>bottom` إذا كان التمرير عموديًا).
	</li>
</ul>
<p>
	إليك صورة تمثيلية تعرض مخرجات (output) الدالّة <code>elem.getBoundingClientRect()‎</code>:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="56634" href="https://academy.hsoub.com/uploads/monthly_2021_01/002getBoundingClientRect.png.3eec429cc92b5a037797d2a2e28da246.png" rel=""><img alt="002getBoundingClientRect.png" class="ipsImage ipsImage_thumbnailed" data-fileid="56634" data-unique="77qldrols" src="https://academy.hsoub.com/uploads/monthly_2021_01/002getBoundingClientRect.png.3eec429cc92b5a037797d2a2e28da246.png"></a>
</p>

<p>
	لاحظ أن الخاصيات <code>x</code> و<code>y</code> و<code>width</code> و<code>height</code> تصف المستطيل وصفًا وافيًا، حيث يمكن حساب بقية الخاصيات المشتقة إنطلاقًا منها:
</p>

<ul>
<li>
		<code>left = x</code>
	</li>
	<li>
		<code>top = y</code>
	</li>
	<li>
		<code>right = x + width</code>
	</li>
	<li>
		<code>bottom = y + height</code>
	</li>
</ul>
<p>
	لاحظ هنا أنه:
</p>

<ul>
<li>
		يمكن للإحداثيات أن تكون أعدادًا عشريةً مثل العدد 10.5. يُعد هذا الأمر عاديًا، حيث يستعمل المتصفح في عمليات الحساب عمليات القسمة، كما أنه ليس علينا تقريب هذه القيم (to round) عند إسنادها للخاصيتين <code>style.left</code> و<code>style.top</code>.
	</li>
	<li>
		يمكن أن تكون قيم الإحداثيات سالبة. في حالة تمرير الصفحة مثلا بحيث يكون العنصر <code>elem</code> تمامًا فوق النافذة، تكون قيمة الخاصية <code>elem.getBoundingClientRect().top</code> سالبة.
	</li>
</ul>
<hr>
<p>
	<strong>ملاحظة: لماذا نحتاج إلى الخاصيات المشتقة؟ وما الهدف من وجود الخاصيتين <code>left</code> و<code>top</code> في وجود الإحداثيات <code>x</code> و<code>y</code>؟</strong>
</p>

<p>
	يُعرّف المستطيل في الرياضيات بإحداثيات نقطة البداية <code>(x,y)</code> وشعاع الاتجاه <code>(width,height)</code>، وبذلك تُستخدَم الخاصيات المشتقة لتسهيل الأمر فقط.
</p>

<p>
	من ناحية تقنية، يمكن أن تكون قيم الخاصيتين<code>width</code> و<code>height</code> سالبة، فهي تسمح بوصف المستطيلات "الموجّهة" وصفًا دقيقًا بما فيها نقطتي البداية والنهاية، كالمستطيلات المتكوّنة عند النقر على الفأرة وسحبها مسافة معيّنة.
</p>

<p>
	وتعني القيم السالبة للخاصيتين <code>width</code> و<code>height</code> أن المستطيل يبدأ من الركن الأيمن السفلي ليتشكّل عن طريق سحب الفأرة في الاتجاه الأيسر نحو الأعلى. وتمثل الصورة الموالية مستطيلًا بقيم سالبة لكل من الخاصيتين <code>width</code> و<code>height</code> (مثال: <code>width=-200, height=-100</code>)
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="56635" href="https://academy.hsoub.com/uploads/monthly_2021_01/003negativeValues.png.32f5e9901a16d9aa97cb2ec85db3af19.png" rel=""><img alt="003negativeValues.png" class="ipsImage ipsImage_thumbnailed" data-fileid="56635" data-unique="ms244uu30" src="https://academy.hsoub.com/uploads/monthly_2021_01/003negativeValues.png.32f5e9901a16d9aa97cb2ec85db3af19.png"></a>
</p>

<p>
	وكما ترى، لا تتطابق قيم الخاصيتين <code>left</code> و<code>top</code> مع قيم الخاصيتين <code>x</code> و<code>y</code> في هذه الحالة. ولكن عمليًا، تُعيد دائمًا الدالّة <code>elem.getBoundingClientRect()‎</code> قيمًا موجبةً للعرض والطول. غير أن السبب الذي حملنا على ذكر القيم السالبة هنا، هو أن هذه القيم التي تبدو لك مكرّرةً، ليست مكرّرةً في الحقيقة.
</p>

<hr>
<p>
	<strong>ملاحظة: لا يدعم المتصفح Internet Explorer الإحداثيات <code>x</code> و<code>y</code></strong>
</p>

<p>
	لا يدعم المتصفح Internet Explorer خاصيتي الإحداثيات <code>x</code> و<code>y</code> لاسباب تاريخية. يمكنك إذًا إمّا استعمال مكتبة بديلة (polyfill) (إضافة جالبات الخاصيات (getters) للخاصية <code>DomRect.prototype</code>) أو استعمال الخاصيتين <code>left</code> و<code>top</code> فقط بما أنهما دائمًا متطابقتين مع الإحداثيات <code>x</code> و<code>y</code> في الحالات التي تكون فيها قيم الخاصيتين <code>width</code> و<code>height</code> موجبة، وخاصة في القيم التي تعيدها الدالّة <code>elem.getBoundingClientRect()‎</code>.
</p>

<hr>
<p>
	<strong>ملاحظة: تختلف الإحداثيات <code>right</code> و<code>bottom</code> عن خاصيات التموضع المعتمدة في شيفرة CSS</strong>
</p>

<p>
	هناك أوجه تشابه جليّة بين الإحداثيات بالنسبة للنافذة، والموضع (<code>position:fixed</code>) المعتمد في شيفرة CSS. ولكن إذا تحدثنا عن التموضع في شيفرة CSS، تمثّل الخاصية <code>right</code> المسافة إنطلاقًا من الركن الأيمن، وتمثّل الخاصية <code>bottom</code> المسافة إنطلاقًا من الركن السفلي.
</p>

<p>
	أمّا إذا تمعّنا في الصورة أعلاه، نُدرك أن الأمر ليس كذلك في لغة جافاسكربت، حيث تُحسب كافة الإحداثيات بالنسبة للنافذة إنطلاقًا من الركن العلوي الأيسر، بما فيها إحداثيات الخاصيتين المذكورتين.
</p>

<hr>
<h2>
	elementFromPoint(x, y)‎
</h2>

<p>
	تعيد الدالّة <code>document.elementFromPoint(x, y)‎</code> العنصر الأكثر تداخلًا مع إحداثيات النافذة <code>(x, y)</code>، وصيغتها كالآتي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5415_7" style="">
<span class="pln">let elem </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">elementFromPoint</span><span class="pun">(</span><span class="pln">x</span><span class="pun">,</span><span class="pln"> y</span><span class="pun">);</span></pre>

<p>
	فعلى سبيل المثال تُلقي هذه الشيفرة الضوء أو تُبرِز وسم العنصر المتموضع وسط النافذة أثناء معاينة الشيفرة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5415_9" style="">
<span class="pln">let centerX </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">documentElement</span><span class="pun">.</span><span class="pln">clientWidth </span><span class="pun">/</span><span class="pln"> </span><span class="lit">2</span><span class="pun">;</span><span class="pln">
let centerY </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">documentElement</span><span class="pun">.</span><span class="pln">clientHeight </span><span class="pun">/</span><span class="pln"> </span><span class="lit">2</span><span class="pun">;</span><span class="pln">
let elem </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">elementFromPoint</span><span class="pun">(</span><span class="pln">centerX</span><span class="pun">,</span><span class="pln"> centerY</span><span class="pun">);</span><span class="pln">
elem</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">background </span><span class="pun">=</span><span class="pln"> </span><span class="str">"red"</span><span class="pun">;</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">elem</span><span class="pun">.</span><span class="pln">tagName</span><span class="pun">);</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-11-Coordinates-ex1" src="https://codepen.io/Hsoub/embed/preview/qBqWLRp?height=265&amp;theme-id=light&amp;default-tab=js,result">See the Pen JS-p2-11-Coordinates-ex1 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	وبما أن الشيفرة تستعمل الإحداثيات بالنسبة للنافذة، يختلف العنصر الذي تُبرزه الشيفرة كلّما جرى تمرير للصفحة.
</p>

<hr>
<p>
	<strong>ملاحظة: تعيد الدالّة<code>elementFromPoint</code> القيمة <code>null</code> إذا مُرِّرَت لها إحداثيات خارجة عن نطاق النافذة</strong>
</p>

<p>
	تعمل الدالّة <code>document.elementFromPoint(x,y)‎</code> فقط إذا كانت الإحداثيات <code>(x,y)</code> المُمَرّرة لها داخل نطاق الجزء من الصفحة الظاهر في النافذة. وإذا كانت إحدى الإحداثيات سالبةً أو خارج نطاق طول أوعرض النافذة، تُعيد الدالّة القيمة <code>null</code>. وإليك نوع الخطأ الذي ينجر عن ذلك:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5415_11" style="">
<span class="pln">let elem </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">elementFromPoint</span><span class="pun">(</span><span class="pln">x</span><span class="pun">,</span><span class="pln"> y</span><span class="pun">);</span><span class="pln">
</span><span class="com">//null القيمة elementFromPoint إذا كانت الإحداثيات خارج نطاق النافذة تعيد الدالّة (elem = null)</span><span class="pln">
elem</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">background </span><span class="pun">=</span><span class="pln"> </span><span class="str">''</span><span class="pun">;</span><span class="pln"> </span><span class="com">// Error!</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-11-Coordinates-ex2" src="https://codepen.io/Hsoub/embed/preview/GRNKPrP?height=265&amp;theme-id=light&amp;default-tab=js,result">See the Pen JS-p2-11-Coordinates-ex2 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<hr>
<h2>
	استعمال الإحداثيات للتموضع الثابت (fixed)
</h2>

<p>
	غالبا ما نحتاج للإحداثيات من أجل إضافة عنصرٍ ما في موضعٍ ما. ولإظهار عنصرٍ بمحاذاة عنصرٍ آخر، يمكننا استعمال الدالّة <code>getBoundingClientRect</code> للحصول على إحداثياته، ثم الاستعانة بالخاصية <code>position</code> مع الخاصيتين <code>left</code> و<code>top</code> (أو <code>right</code> و<code>bottom</code>).
</p>

<p>
	فعلى سبيل المثال، تُظهر الدالّة <code>createMessageUnder(elem, html)‎</code> في الشيفرة الموالية رسالةً تحت العنصر <code>elem</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5415_13" style="">
<span class="pln">let elem </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">"coords-show-mark"</span><span class="pun">);</span><span class="pln">
</span><span class="kwd">function</span><span class="pln"> createMessageUnder</span><span class="pun">(</span><span class="pln">elem</span><span class="pun">,</span><span class="pln"> html</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">//  إنشاء العنصر الذي يضم الرسالة</span><span class="pln">
  let message </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">createElement</span><span class="pun">(</span><span class="str">'div'</span><span class="pun">);</span><span class="pln">
  </span><span class="com">//يستحسن استعمال صنف CSS لتحديد النمط التنسيقي</span><span class="pln">
  message</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">cssText </span><span class="pun">=</span><span class="pln"> </span><span class="str">"position:fixed; color: red"</span><span class="pun">;</span><span class="pln">
  </span><span class="com">//إسناد الإحداثيات دون أن ننسى الحرفين 'px'</span><span class="pln">
  let coords </span><span class="pun">=</span><span class="pln"> elem</span><span class="pun">.</span><span class="pln">getBoundingClientRect</span><span class="pun">();</span><span class="pln">
  message</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">left </span><span class="pun">=</span><span class="pln"> coords</span><span class="pun">.</span><span class="pln">left </span><span class="pun">+</span><span class="pln"> </span><span class="str">"px"</span><span class="pun">;</span><span class="pln">
  message</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">top </span><span class="pun">=</span><span class="pln"> coords</span><span class="pun">.</span><span class="pln">bottom </span><span class="pun">+</span><span class="pln"> </span><span class="str">"px"</span><span class="pun">;</span><span class="pln">
  message</span><span class="pun">.</span><span class="pln">innerHTML </span><span class="pun">=</span><span class="pln"> html</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> message</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="com">// :الاستعمال</span><span class="pln">
</span><span class="com">// إضافته للصفحة لمدّة خمس ثوان </span><span class="pln">
let message </span><span class="pun">=</span><span class="pln"> createMessageUnder</span><span class="pun">(</span><span class="pln">elem</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Hello, world!'</span><span class="pun">);</span><span class="pln">
document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">append</span><span class="pun">(</span><span class="pln">message</span><span class="pun">);</span><span class="pln">
setTimeout</span><span class="pun">(()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> message</span><span class="pun">.</span><span class="pln">remove</span><span class="pun">(),</span><span class="pln"> </span><span class="lit">5000</span><span class="pun">);</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-11-Coordinates-ex3" src="https://codepen.io/Hsoub/embed/preview/VwmZqpd?height=265&amp;theme-id=light&amp;default-tab=js,result">See the Pen JS-p2-11-Coordinates-ex3 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	عند الضغط على الزر صاحب الخاصية <code>id="coords-show-mark"‎</code> تظهر الرسالة تحته.
</p>

<p>
	يمكن التعديل على الشيفرة لإظهار الرسالة على اليسار، أو على اليمين، أو في الأسفل، أو تطبيق شيفرة حركات CSS (أي CSS animation) عليه لجعله يختفي تدريجيا، وهكذا دواليك. سيكون ذلك سهلًا طالما نملك كافة إحداثيات ومقاسات العنصر.
</p>

<p>
	لاحظ هذا التفصيل المهم: في حالة ما إذا قمنا بتمرير الصفحة تبتعد الرسالة عن الزر. والسبب واضح: موضع الرسالة ثابت (<code>position:fixed</code>)، لذا تبقى في نفس الموضع من النافذة عند تمرير الصفحة. ولتغيير ذلك، علينا استعمال الإحداثيات بالنسبة للصفحة، والموضع المطلق (<code>position:absolute</code>).
</p>

<h2>
	إحداثيات الصفحة
</h2>

<p>
	يبدأ احتساب الإحداثيات بالنسبة للصفحة من الركن العلوي الأيسر للصفحة، لا النافذة. ويقابِل الإحداثيات بالنسبة للنافذة في لغة CSS الموضع <code>position:fixed</code>، أما الإحداثيات بالنسبة للصفحة فيقابلها في لغة CSS الموضع <code>position:absolute</code> من الأعلى.
</p>

<p>
	يمكننا استعمال الموضع <code>position:absolute</code> والخاصيتين <code>left</code> و<code>top</code> لوضع عنصرٍ ما في موضعٍ ما من الصفحة ، بحيث يبقى في نفس الموضع عند تمرير الصفحة. ولكن علينا أولا إيجاد الإحداثيات الصحيحة.
</p>

<p>
	لا يوجد أيّ دالّة في المعايير تسمح بالحصول على إحداثيات عنصرٍ ما بالنسبة للصفحة، ولكن يمكننا كتابتها.<br>
	يعد نظامي الإحداثيات مرتبطين ببعضهما البعض من خلال المعادلة التالية:
</p>

<ul>
<li>
		<code>pageY</code>=<code>clientY</code>+ طول الجزء العمودي من الصفحة غير الظاهر في النافذة.
	</li>
	<li>
		<code>pageX</code>=<code>clientX</code>+ عرض الجزء الأفقي من الصفحة غير الظاهر في النافذة.
	</li>
</ul>
<p>
	تأخذ الدالّة <code>getCoords(elem)‎</code> الإحداثيات بالنسبة للنافذة باستخدام الدالّة <code>elem.getBoundingClientRect()‎</code> وتضيف مسافة التمرير لها.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5415_15" style="">
<span class="com">//  الحصول على إحداثيات العنصر بالنسبة للصفحة</span><span class="pln">
</span><span class="kwd">function</span><span class="pln"> getCoords</span><span class="pun">(</span><span class="pln">elem</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  let box </span><span class="pun">=</span><span class="pln"> elem</span><span class="pun">.</span><span class="pln">getBoundingClientRect</span><span class="pun">();</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    top</span><span class="pun">:</span><span class="pln"> box</span><span class="pun">.</span><span class="pln">top </span><span class="pun">+</span><span class="pln"> window</span><span class="pun">.</span><span class="pln">pageYOffset</span><span class="pun">,</span><span class="pln">
    right</span><span class="pun">:</span><span class="pln"> box</span><span class="pun">.</span><span class="pln">right </span><span class="pun">+</span><span class="pln"> window</span><span class="pun">.</span><span class="pln">pageXOffset</span><span class="pun">,</span><span class="pln">
    bottom</span><span class="pun">:</span><span class="pln"> box</span><span class="pun">.</span><span class="pln">bottom </span><span class="pun">+</span><span class="pln"> window</span><span class="pun">.</span><span class="pln">pageYOffset</span><span class="pun">,</span><span class="pln">
    left</span><span class="pun">:</span><span class="pln"> box</span><span class="pun">.</span><span class="pln">left </span><span class="pun">+</span><span class="pln"> window</span><span class="pun">.</span><span class="pln">pageXOffset
  </span><span class="pun">};</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	في المثال أعلاه، استعملنا الموضع <code>position:absolute</code>، وبذلك تبقى الرسالة بمحاذاة العنصر عند تمرير الصفحة وتصبح الدالّة <code>createMessageUnder</code> بعد التعديل كالآتي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5415_17" style="">
<span class="kwd">function</span><span class="pln"> createMessageUnder</span><span class="pun">(</span><span class="pln">elem</span><span class="pun">,</span><span class="pln"> html</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  let message </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">createElement</span><span class="pun">(</span><span class="str">'div'</span><span class="pun">);</span><span class="pln">
  message</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">cssText </span><span class="pun">=</span><span class="pln"> </span><span class="str">"position:absolute; color: red"</span><span class="pun">;</span><span class="pln">
  let coords </span><span class="pun">=</span><span class="pln"> getCoords</span><span class="pun">(</span><span class="pln">elem</span><span class="pun">);</span><span class="pln">
  message</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">left </span><span class="pun">=</span><span class="pln"> coords</span><span class="pun">.</span><span class="pln">left </span><span class="pun">+</span><span class="pln"> </span><span class="str">"px"</span><span class="pun">;</span><span class="pln">
  message</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">top </span><span class="pun">=</span><span class="pln"> coords</span><span class="pun">.</span><span class="pln">bottom </span><span class="pun">+</span><span class="pln"> </span><span class="str">"px"</span><span class="pun">;</span><span class="pln">
  message</span><span class="pun">.</span><span class="pln">innerHTML </span><span class="pun">=</span><span class="pln"> html</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> message</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<h2>
	الخلاصة
</h2>

<p>
	لكلّ نقطة من الصفحة إحداثيات:
</p>

<ol>
<li>
		بالنسبة للنافذة: تُساوي <code>elem.getBoundingClientRect()‎</code>
	</li>
	<li>
		بالنسبة للصفحة: تُساوي <code>elem.getBoundingClientRect()‎</code> + مقدار تمرير الصفحة.
	</li>
</ol>
<p>
	يُنصح باستخدام الإحداثيات بالنسبة للنافذة مع الموضع <code>position:fixed</code>، والإحداثيات بالنسبة للصفحة مع الموضع <code>position:absolute</code>. ولِكِلَا نظامي الإحداثيات إيجابيات وسلبيات، حيث يُستحسن استعمال أحدهما في حالات معيّنة، والآخر في حالات أخرى، كما هو الحال بالنسبة للمواضع <code>absolute</code> و<code>fixed</code> في لغة CSS.
</p>

<h2>
	تمارين
</h2>

<h3>
	إيجاد إحداثيات المستطيل بالنسبة للنافذة
</h3>

<p>
	<em>درجة الأهمية:</em>5
</p>

<p>
	لدينا في الصورة الموالية صفحة ويب بها مستطيل أخضر “field”. استعمل لغة جافاسكربت للحصول على إحداثيات الأركان المؤشر عليها بالأسهم الحمراء بالنسبة للنافذة.
</p>

<p>
	أضيفت للصفحة إمكانية الحصول على إحداثيات أيّ نقطة منها بمجرد النقر عليها لتسهيل الأمر عليك.
</p>

<p>
	يمكنك الاطلاع على شيفرة التمرين عبر هذا <a href="https://plnkr.co/edit/EDtjdNk6S43g1SAB?p=preview&amp;preview" rel="external nofollow">الرابط</a>
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="56636" href="https://academy.hsoub.com/uploads/monthly_2021_01/004greenField.png.a05de2183593e57a0e4a357588002887.png" rel=""><img alt="004greenField.png" class="ipsImage ipsImage_thumbnailed" data-fileid="56636" data-unique="kxz5wwv8w" src="https://academy.hsoub.com/uploads/monthly_2021_01/004greenField.png.a05de2183593e57a0e4a357588002887.png"></a>
</p>

<p>
	عليك استعمال نموذج تمثيل الصفحة ككائن DOM للحصول على الإحداثيات بالنسبة للنافذة لكل من:
</p>

<ul>
<li>
		الركن الخارجي العلوي الأيسر (وهو سهل).
	</li>
	<li>
		الركن الخارجي السفلي الأيمن (وهو سهل أيضا).
	</li>
	<li>
		الركن الداخلي العلوي الأيسر (صعب بعض الشيء).
	</li>
	<li>
		الركن الداخلي السفلي الأيمن ( هناك عدة طرائق للحصول عليه. اختر واحدة منها)
	</li>
</ul>
<p>
	ينبغي أن تكون الإحداثيات التي تحسبها الشيفرة متطابقةً مع الإحداثيات التي تظهر عند النقر على الركن بالفأرة. ينبغي أيضًا أن تعمل الشيفرة مهما كانت قيم المقاسات والأطر، ليس فقط من أجل القيم المعطاة في نص التمرين.
</p>

<h4>
	<strong>الحل</strong>
</h4>

<h5>
	الركنان الخارجيان
</h5>

<p>
	تكون إحداثيات الركنين الخارجيين عادةً هي الإحداثيات التي تعيدها الدالّة <a href="https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect" rel="external nofollow">elem.getBoundingClientRect()‎</a>.
</p>

<p>
	في الشيفرة التالية، تمثّل <code>answer1</code> إحداثيات الركن العلوي الأيسر، وتمثّل <code>answer2</code> إحداثيات الركن السفلي الأيمن.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5415_19" style="">
<span class="pln">let coords </span><span class="pun">=</span><span class="pln"> elem</span><span class="pun">.</span><span class="pln">getBoundingClientRect</span><span class="pun">();</span><span class="pln">
let answer1 </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">coords</span><span class="pun">.</span><span class="pln">left</span><span class="pun">,</span><span class="pln"> coords</span><span class="pun">.</span><span class="pln">top</span><span class="pun">];</span><span class="pln">
let answer2 </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">coords</span><span class="pun">.</span><span class="pln">right</span><span class="pun">,</span><span class="pln"> coords</span><span class="pun">.</span><span class="pln">bottom</span><span class="pun">];</span></pre>

<h5>
	الركن الداخلي العلوي الأيسر
</h5>

<p>
	الفرق بينه وبين الركن الخارجي هو عرض الإطار. والطريقة المثلى للحصول على هذه المسافة هي باستعمال الخاصيتين <code>clientLeft</code> و<code>clientTop</code>.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5415_21" style="">
<span class="pln">let answer3 </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">coords</span><span class="pun">.</span><span class="pln">left </span><span class="pun">+</span><span class="pln"> field</span><span class="pun">.</span><span class="pln">clientLeft</span><span class="pun">,</span><span class="pln"> coords</span><span class="pun">.</span><span class="pln">top </span><span class="pun">+</span><span class="pln"> field</span><span class="pun">.</span><span class="pln">clientTop</span><span class="pun">];</span></pre>

<h5>
	الركن الداخلي السفلي الأيمن
</h5>

<p>
	علينا في هذه الحالة طرح عرض الإطار من الإحداثيات الخارجية. ويمكننا استعمال لغة CSS كالآتي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5415_23" style="">
<span class="pln">let answer4 </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
  coords</span><span class="pun">.</span><span class="pln">right </span><span class="pun">-</span><span class="pln"> parseInt</span><span class="pun">(</span><span class="pln">getComputedStyle</span><span class="pun">(</span><span class="pln">field</span><span class="pun">).</span><span class="pln">borderRightWidth</span><span class="pun">),</span><span class="pln">
  coords</span><span class="pun">.</span><span class="pln">bottom </span><span class="pun">-</span><span class="pln"> parseInt</span><span class="pun">(</span><span class="pln">getComputedStyle</span><span class="pun">(</span><span class="pln">field</span><span class="pun">).</span><span class="pln">borderBottomWidth</span><span class="pun">)</span><span class="pln">
</span><span class="pun">];</span></pre>

<p>
	هناك أيضًا طريقةٌ بديلةٌ، وربما هي أحسن، تكون بإضافة قيم الخاصيتين <code>clientWidth</code> و<code>clientHeight</code> لإحداثيات الركن العلوي الأيسر.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5415_25" style="">
<span class="pln">let answer4 </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
  coords</span><span class="pun">.</span><span class="pln">left </span><span class="pun">+</span><span class="pln"> elem</span><span class="pun">.</span><span class="pln">clientLeft </span><span class="pun">+</span><span class="pln"> elem</span><span class="pun">.</span><span class="pln">clientWidth</span><span class="pun">,</span><span class="pln">
  coords</span><span class="pun">.</span><span class="pln">top </span><span class="pun">+</span><span class="pln"> elem</span><span class="pun">.</span><span class="pln">clientTop </span><span class="pun">+</span><span class="pln"> elem</span><span class="pun">.</span><span class="pln">clientHeight
</span><span class="pun">];</span></pre>

<p>
	يمكنك الاطلاع على شيفرة الحل عبر هذا <a href="https://plnkr.co/edit/K35otM66PlWyBgbb?p=preview&amp;preview" rel="external nofollow">الرابط</a>
</p>

<h3>
	إظهار ملاحظة بمحاذاة عنصرٍ ما
</h3>

<p>
	<em>درجة الأهمية: 5</em>
</p>

<p>
	أنشئ الدالّة <code>positionAt(anchor, position, elem)‎</code> التي تضع العنصر<code>elem</code> في موضعٍ <code>position</code> قريبٍ من العنصر<code>anchor</code>.
</p>

<p>
	يكون الموضع <code>position</code> عبارة عن سلسلة نصية ويأخذ إحدى القيم التالية:
</p>

<ul>
<li>
		<code>"top"</code>: تضع العنصر <code>elem</code> فوق العنصر<code>anchor</code> مباشرة.
	</li>
	<li>
		<code>"right"</code>: تضع العنصر<code>elem</code> على يمين العنصر<code>anchor</code> مباشرة.
	</li>
	<li>
		<code>"bottom"</code>: تضع العنصر<code>elem</code> أسفل العنصر <code>anchor</code> مباشرة.
	</li>
</ul>
<p>
	تُستعمل هذه الدالّة بداخل الدالّة <code>showNote(anchor, position, html)‎</code> (الشيفرة الخاصة بالدالّة معطاة في نص التمرين) التي تُنشئ عنصرًا يحتوي على ملاحظة من خلال الشيفرة <code>html</code> المُمَرّرة لها، وتظهر هذه الملاحظة في الموضع <code>position</code> المُمَرر لها بمحاذاة العنصر <code>anchor</code>، وهذه صورة تمثيلية للنتيجة التي نريد الوصول اليها:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="56637" href="https://academy.hsoub.com/uploads/monthly_2021_01/005nearAnchorPosition.png.05963d2192e7e36e054de8012390fa74.png" rel=""><img alt="005nearAnchorPosition.png" class="ipsImage ipsImage_thumbnailed" data-fileid="56637" data-unique="y83q5ltwa" src="https://academy.hsoub.com/uploads/monthly_2021_01/005nearAnchorPosition.png.05963d2192e7e36e054de8012390fa74.png"></a>
</p>

<p>
	يمكنك الاطلاع على شيفرة التمرين عبر هذا <a href="https://plnkr.co/edit/nwn7WjPXNeRuuTg8?p=preview&amp;preview" rel="external nofollow">الرابط</a>.
</p>

<h4>
	<strong>الحل</strong>
</h4>

<p>
	في هذا التمرين نحتاج فقط حسابَ الإحداثيات بشكلٍ دقيقٍ. ولتفاصيل أكثر، اطلع على شيفرة الحل. لاحظ أن العناصر ينبغي أن تكون موجودةً في الصفحة حتى يتسنى لنا قراءة الخاصية <code>offsetHeight</code> وخاصيات أخرى. حيث أن العنصر المخفي (<code>display:none</code>) أو غير الموجود بالصفحة لا يملك مقاسات.
</p>

<p>
	يمكنك الاطلاع على الحل عبر هذا <a href="https://plnkr.co/edit/VyAb5Fjkqui3CRmS?p=preview&amp;preview" rel="external nofollow">الرابط</a>.
</p>

<h3>
	إظهار ملاحظة بمحاذاة عنصرٍ ما (مطلق)
</h3>

<p>
	<em>درجة الأهمية: 5</em>
</p>

<p>
	عدِّل على حل التمرين السابق بحيث تستعمل الملاحظة موضعًا مطلقًا (<code>position:absolute</code>) بدلًا من الموضع الثابت (<code>position:fixed</code>). هذا ما يُبقِي الملاحظة بمحاذاة العنصر عند تمرير الصفحة.
</p>

<p>
	استعمل حل التمرين السابق كنقطة انطلاق، ولمعاينة التمرين أضف النمط التنسيقي التالي: <code>&lt;body style="height: 2000px"‎&gt;</code>
</p>

<h4>
	<strong>الحل</strong>
</h4>

<p>
	الحل بسيطٌ جدًا.
</p>

<ul>
<li>
		غيّر الخاصية <code>position</code> الخاصة بالمحدِّد <code>.note</code> من <code>position:fixed</code> إلى<code>position:absolute</code> في شيفرة CSS.
	</li>
	<li>
		استعمل الدالّة <code>getCoords()‎</code> المعرّفة أعلاه للحصول على الإحداثيات بالنسبة للصفحة.
	</li>
</ul>
<p>
	يمكنك الإطلاع على الحل عبر هذا <a href="https://plnkr.co/edit/IltvUDuUTs6bVjl3?p=preview&amp;preview" rel="external nofollow">الرابط</a>.
</p>

<h3>
	وضع الملاحظة داخل العنصر (مطلق)
</h3>

<p>
	<em>درجة الأهمية: 5</em>
</p>

<p>
	استعمل التمرين السابق (إظهار ملاحظة بمحاذاة عنصرٍ ما [مطلق]) وعدّل على الدالّة <code>positionAt(anchor, position, elem)‎</code> لتسمح بإضافة عنصر <code>elem</code> داخل العنصر<code>anchor</code>.
</p>

<p>
	والقيم الجديدة للموضع <code>position</code> هي:
</p>

<ul>
<li>
		<code>bottom-out</code> ،<code>right-out</code> ،<code>top-out</code>: هي نفس المواضع المعرّفة في الحل الأول والتي تسمح بإضافة العنصر<code>elem</code> فوق أو على يمين أو تحت العنصر <code>anchor</code>.
	</li>
	<li>
		<code>bottom-in</code>، <code>right-in</code>، <code>top-in</code>: تسمح بإضافة العنصر <code>elem</code> داخل العنصر <code>anchor</code> بحيث يلتصق بالركن العلوي أو الأيمن أو السفلي.
	</li>
</ul>
<p>
	على سبيل المثال:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5415_27" style="">
<span class="com">// تظهر الملاحظة فوق إطار المقولة</span><span class="pln">
positionAt</span><span class="pun">(</span><span class="pln">blockquote</span><span class="pun">,</span><span class="pln"> </span><span class="str">"top-out"</span><span class="pun">,</span><span class="pln"> note</span><span class="pun">);</span><span class="pln">

</span><span class="com">// تظهر الملاحظة داخل إطار المقولة في الأعلى</span><span class="pln">
positionAt</span><span class="pun">(</span><span class="pln">blockquote</span><span class="pun">,</span><span class="pln"> </span><span class="str">"top-in"</span><span class="pun">,</span><span class="pln"> note</span><span class="pun">);</span></pre>

<p>
	والنتيجة تكون كالآتي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="56638" href="https://academy.hsoub.com/uploads/monthly_2021_01/006inAnchorPosition.png.cb7c2b9315863daa6ada124edf35da5f.png" rel=""><img alt="006inAnchorPosition.png" class="ipsImage ipsImage_thumbnailed" data-fileid="56638" data-unique="pe0jt1t09" src="https://academy.hsoub.com/uploads/monthly_2021_01/006inAnchorPosition.png.cb7c2b9315863daa6ada124edf35da5f.png"></a>
</p>

<p>
	خذ شيفرة حل التمرين السابق (إظهار ملاحظة بمحاذاة عنصرٍ ما [مطلق]) واستعن بها كشيفرة نص لهذا التمرين.
</p>

<h4>
	<strong>الحل</strong>
</h4>

<p>
	يمكنك الاطلاع على الحل عبر هذا <a href="https://plnkr.co/edit/KkS3sLDgUKFy4XUU?p=preview&amp;preview" rel="external nofollow">الرابط</a>.
</p>

<p>
	ترجمة -وبتصرف- للفصل <a href="https://javascript.info/coordinates" rel="external nofollow">Coordinates</a> من كتاب <a href="https://javascript.info/ui" rel="external nofollow">Browser: Document, Events, Interfaces</a>
</p>
]]></description><guid isPermaLink="false">1121</guid><pubDate>Fri, 29 Jan 2021 13:31:48 +0000</pubDate></item><item><title>&#x636;&#x628;&#x637; &#x645;&#x642;&#x627;&#x633;&#x627;&#x62A; &#x646;&#x627;&#x641;&#x630;&#x629; &#x635;&#x641;&#x62D;&#x629; &#x627;&#x644;&#x648;&#x64A;&#x628; &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A; &#x648;&#x627;&#x631;&#x62A;&#x628;&#x627;&#x637;&#x647;&#x627; &#x628;&#x639;&#x645;&#x644;&#x64A;&#x629; &#x627;&#x644;&#x62A;&#x645;&#x631;&#x64A;&#x631; (scrolling)</title><link>https://academy.hsoub.com/programming/javascript/%D8%B6%D8%A8%D8%B7-%D9%85%D9%82%D8%A7%D8%B3%D8%A7%D8%AA-%D9%86%D8%A7%D9%81%D8%B0%D8%A9-%D8%B5%D9%81%D8%AD%D8%A9-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-%D9%88%D8%A7%D8%B1%D8%AA%D8%A8%D8%A7%D8%B7%D9%87%D8%A7-%D8%A8%D8%B9%D9%85%D9%84%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D9%85%D8%B1%D9%8A%D8%B1-scrolling-r1120/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_01/601406831bbe6_----()--.png.43cd223f70f625423bed5dab7049f76d.png" /></p>

<p>
	هل تتساءل عن كيفية الحصول على طول وعرض نافذة المتصفح؟ وكيف لك أن تعرف الطول والعرض الكلي للصفحة بما فيه الجزء الذي لا يُؤشِر عليه شريط التمرير (الجزء من الصفحة غير الظاهر في النافذة)؟ وكيف يمكن تمرير محتوى الصفحة باستعمال لغة جافاسكربت؟ فيما يلي الأجوبة الشافية لكل هذه التساؤلات.
</p>

<p>
	يمكن، في أغلب هذه الحالات، استعمال العنصر الجذر للصفحة <code>document.documentElement</code> الذي يقابِل الوسم <code>&lt;html&gt;</code>، بالإضافة إلى بعض الدوالّ والخاصيات التي يُستحسن أخذها في الحسبان نظرًا لأهميتها.
</p>

<h2>
	طول وعرض النافذة
</h2>

<p>
	تُستخدم الخاصيتان <code>clientHeight</code> و<code>clientWidth</code> لمعرفة طول وعرض النافذة.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2021_01/001documentElementClientHeightWidth.png.f620528c1fa475d49043adc8c0b35799.png" data-fileid="56630" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="56630" data-unique="ci7bdgms3" src="https://academy.hsoub.com/uploads/monthly_2021_01/001documentElementClientHeightWidth.png.f620528c1fa475d49043adc8c0b35799.png" alt="001documentElementClientHeightWidth.png"></a>
</p>

<p>
	حيث تُظهِرالتعليمة، في المثال التالي، طول نافذة المتصفح:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7112_7" style="">
<span class="pln">alert</span><span class="pun">(</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">documentElement</span><span class="pun">.</span><span class="pln">clientHeight </span><span class="pun">);</span></pre>

<hr>
<p>
	<strong>ملاحظة: لا تستعمل window.innerWidth وwindow.innerHeight</strong>
</p>

<p>
	تدعم المتصفحات الخاصيتين <code>window.innerWidth</code> و<code>window.innerHeight</code>، ويبدو أنهما تتوافقان مع ما نريده، فلماذا لا نستخدمهما بدلًا من الخاصيتين اللّتان ذكرناهما سابقا؟
</p>

<p>
	في حالة وجود شريط تمرير في الصفحة، تعطي الخاصيتان <code>clientHeight</code> و<code>clientWidth</code> طول وعرض النافذة بعد طرح عرض شريط التمرير منه. أو بعبارة أخرى، تعطيان طول وعرض الجزء الظاهر من الصفحة والمخصص للمحتوى. وتعطي الخاصيتان <code>window.innerWidth</code> و<code>window.innerHeight</code> الطول والعرض الكليين للنافذة بما فيهما عرض شريط التمرير.
</p>

<p>
	في حالة ما إذا كان لدينا شريط تمرير يشغل مساحة ما من النافذة، تعطي التعليمتان التاليتان نتائج مختلفة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7112_9" style="">
<span class="pln">alert</span><span class="pun">(</span><span class="pln"> window</span><span class="pun">.</span><span class="pln">innerWidth </span><span class="pun">);</span><span class="pln"> </span><span class="com">// العرض الكلي للنافذة</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">documentElement</span><span class="pun">.</span><span class="pln">clientWidth </span><span class="pun">);</span><span class="pln"> </span><span class="com">// عرض النافذة بعد طرح عرض شريط التمرير منه</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" src="https://codepen.io/Hsoub/embed/preview/yLVBGVe?height=265&amp;theme-id=light&amp;default-tab=js,result" style="width: 100%;" title="JS-p2-10-Window sizes and scrolling-ex1">See the Pen JS-p2-10-Window sizes and scrolling-ex1 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	نحتاج، في أغلب الحالات، معرفة عرض النافذة المتاح (المخصص للمحتوى)، لرسم شيء ما أو وضعه، أي دون احتساب عرض شريط التمرير إن وُجد، لذا علينا استعمال الخاصيتين <code>documentElement.clientHeight</code> و<code>documentElement.clientWidth</code>.
</p>

<hr>
<p>
	<strong>ملاحظة: التعليمة DOCTYPE مهمة</strong>
</p>

<p>
	لاحظ أن الخاصيات رفيعة المستوى المتعلقة بالهندسة يمكن أن لا تعمل بالشكل المطلوب إذا لم يحوي ملف HTML التعليمة <code>&lt;!DOCTYPE HTML&gt;</code> ، فمن الممكن أن تحدث أشياء غريبة بسبب ذلك. أضف دائمًا إذًا التعليمة <code>DOCTYPE</code> عند كتابة شيفرة HTML على الطريقة العصرية.
</p>

<hr>
<h2>
	طول وعرض الصفحة
</h2>

<p>
	نظريا، وبما أن العنصر الجذر للصفحة هو <code>document.documentElement</code>، ويضُم كلّ المحتوى، يمكن قياس العرض والطول الكليين للصفحة باستعمال الخاصيتين <code>document.documentElement.scrollWidth</code> و<code>document.documentElement.scrollHeight</code>، ولكن هاتين الخاصيتين، عند استعمالهما على هذا العنصر، لا تعملان بالشكل المطلوب إن لم يكن هناك شريط تمرير في كلّ من المتصفحات Chrome/Safari/Opera، حيث يمكن أن تعطي الخاصية <code>documentElement.scrollHeight</code> قيمةً أصغر من القيمة التي تعطيها الخاصية <code>documentElement.clientHeight</code>. يبدو الأمر غريبا نوعا ما، أليس كذلك؟
</p>

<p>
	للحصول إذًا على القيمة الصحيحة للطول الكلي للصفحة، علينا أخذ أكبر قيمة من بين القيم التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7112_11" style="">
<span class="pln">let scrollHeight </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">max</span><span class="pun">(</span><span class="pln">
  document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">scrollHeight</span><span class="pun">,</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">documentElement</span><span class="pun">.</span><span class="pln">scrollHeight</span><span class="pun">,</span><span class="pln">
  document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">offsetHeight</span><span class="pun">,</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">documentElement</span><span class="pun">.</span><span class="pln">offsetHeight</span><span class="pun">,</span><span class="pln">
  document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">clientHeight</span><span class="pun">,</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">documentElement</span><span class="pun">.</span><span class="pln">clientHeight
</span><span class="pun">);</span><span class="pln">
alert</span><span class="pun">(</span><span class="str">'Full document height, with scrolled out part: '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> scrollHeight</span><span class="pun">);</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" src="https://codepen.io/Hsoub/embed/preview/qBqWLqp?height=265&amp;theme-id=light&amp;default-tab=js,result" style="width: 100%;" title="JS-p2-10-Window sizes and scrolling-ex2">See the Pen JS-p2-10-Window sizes and scrolling-ex2 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	لماذا يحدث ذلك؟ يُستحسن عدم طرح هذا السؤال لأن هذه التناقضات موجودة منذ زمن ولا تخضع لتفكير منطقي "ذكي".
</p>

<h2>
	حساب إحداثيات الموضع الحالي لعنصر ما
</h2>

<p>
	تملك عناصر تمثيل الصفحة ككائن DOM خاصيتين تحملان إحداثيات موضعها من الصفحة وهما: <code>elem.scrollLeft</code> و<code>elem.scrollTop</code>. فبالنسبة لموضِع النافذة، تعمل الخاصيتان <code>document.documentElement.scrollLeft</code> و<code>document.documentElement.scrollTop</code> في أغلب المتصفحات، عدا تلك التي تعتمد على محرك WebKit مثل المتصفح <code>Safari</code> (يوّلد استعمالها الخطأ البرمجي 5991)، حيث ينبغي في هذه الحالة استعمال <code>document.body</code> بدلا من <code>document.documentElement</code>.
</p>

<p>
	ومن حسن الحظ أنه ليس علينا على الإطلاق تذكُّر كلّ هذه الخاصيات، حيث توجد خاصيتان غيرهما تعطيان الموضع الحالي للنافدة، إنهما الخاصيتان <code>window.pageXOffset</code> و<code>window.pageYOffset</code>، وهما خاصيتان قابلتان فقط للقراءة.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7112_13" style="">
<span class="pln">alert</span><span class="pun">(</span><span class="str">'Current scroll from the top: '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> window</span><span class="pun">.</span><span class="pln">pageYOffset</span><span class="pun">);</span><span class="pln">
alert</span><span class="pun">(</span><span class="str">'Current scroll from the left: '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> window</span><span class="pun">.</span><span class="pln">pageXOffset</span><span class="pun">);</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" src="https://codepen.io/Hsoub/embed/preview/RwobEoe?height=265&amp;theme-id=light&amp;default-tab=js,result" style="width: 100%;" title="JS-p2-10-Window sizes and scrolling-ex3">See the Pen JS-p2-10-Window sizes and scrolling-ex3 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<h2>
	التمرير باستعمال الدوال scrollTo وscrollBy وscrollIntoView
</h2>

<hr>
<p>
	<strong>ملاحظة هامة</strong>
</p>

<p>
	لا يمكن تمرير الصفحة إلّا بعد البناء الكلي لنموذج تمثيل الصفحة ككائن (DOM)، فمن غير الممكن كتابة شيفرة لتمرير الصفحة ووضعها في الجزء <code>&lt;head&gt;</code> أي تنفيذها قبل أن تجهز الصفحة فلن يعمل ذلك حتما.
</p>

<hr>
<p>
	ويمكن تمرير العناصر العادية بتغيير قيم الخاصيتين <code>scrollTop</code> و<code>scrollLeft</code>، كما يمكن عمل الشيء نفسه للصفحة باستعمال الخاصيتين <code>document.documentElement.scrollLeft</code> و<code>document.documentElement.scrollTop</code>، عدا في المتصفح <code>Safari</code> (حيث ينبغي استخدام الخاصيتين <code>document.body.scrollLeft</code> و<code>document.body.scrollTop</code> بدلا منها).
</p>

<p>
	وهناك أيضا طريقةٌ بديلةٌ، أبسط من الأولى، تعمل في كافة المتصفحات، وتكون باستعمال الدالّتين <code>window.scrollBy(x,y)‎</code> و<code>window.scrollTo(pageX,pageY)‎</code>.
</p>

<p>
	تحرّك الدالّة <code>scrollBy(x,y)‎</code> النافذة من مكانها الحالي بمقدار معين. حيث تُحرِك التعليمة <code>window.scrollBy(0,10)‎</code> مثلا الصفحة إلى الأسفل بمقدار عشرة بكسل.
</p>

<p>
	وتحرِّك الدالّة <code>scrollTo(pageX,pageY)‎</code> الصفحة إلى موضعٍ ذي إحداثياتٍ مطلقةٍ. بحيث تكون إحداثيات الركن العلوي الأيسر للجزء الظاهر من الصفحة هي <code>(pageX, pageY)</code> إنطلاقا من الركن العلوي الأيسر للصفحة. تعمل هذه الدالّة تماما كما لو أننا نُسنِد قِيَمًا للخاصيتين <code>scrollLeft</code> و<code>scrollTop</code>.
</p>

<p>
	مثلًا لتحريك النافذة إلى نقطة البداية (العودة إلى أعلى الصفحة)، يمكن استعمال التعليمة <code>window.scrollTo(0,0)‎</code>. وتعمل هذه الدوالّ بنفس الطريقة (تعطي النتائج نفسها) على كلّ المتصفحات.
</p>

<h3>
	الدالة scrollIntoView
</h3>

<p>
	دعنا نكمل ما بدأناه بشرح الدالّة <code>elem.scrollIntoView(top)‎</code>. ينتج عن مناداة هذه الدالّة تمرير الصفحة بحيث تجعل العنصر <code>elem</code> ظاهرًا، ولها وسيط واحد:
</p>

<ul>
<li>
		إذا كانت قيمة الوسيط <code>top</code> تساوي <code>true</code> (وهي القيمة المبدئية -الافتراضية)، تُمرَّر الصفحة بحيث يظهر العنصر <code>elem</code> أعلى النافذة فتتطابق حافته العلوية مع أعلى النافذة.
	</li>
	<li>
		وإذا كانت قيمة الوسيط <code>top</code> تساوي <code>false</code>، تُمرَّر الصفحة بحيث يظهر العنصر <code>elem</code> أسفل النافذة فتتطابق حافته السفلى مع أسفل النافذة.
	</li>
</ul>
<p>
	مثال: إذا كان لدينا زر، فإن هذه التعليمة <code>this.scrollIntoView()‎</code> تُحرِك الصفحة بحيث يظهر هذا الزر أعلى النافذة. أما هذه التعليمة <code>this.scrollIntoView(false)‎</code>، فتُحرِك الصفحة بحيث يظهر الزر أسفل النافذة.
</p>

<h2>
	تثبيط قابلية التمرير
</h2>

<p>
	نحتاج أحيانا إلى جعل الصفحة غير قابلة للتمرير، فنرغب مثلًا في إخفائها وراء رسالة طويلة للفت انتباه الزائر وحمله على التفاعل مع الرسالة وليس مع الصفحة. وهنا يكفي إسناد القيمة <code>"hidden"</code> للخاصية <code>document.body.style.overflow</code> حيث تثبِّت (تجمِّد) هذه التعليمة الصفحة في موضعها الحالي.
</p>

<p>
	فلتجرب ذلك باستعمال التعليمتين <code>document.body.style.overflow="hidden"</code> و <code>document.body.style.overflow=""</code>.
</p>

<p>
	هنا، تثبِّط التعليمة الأولى قابلية التحريك، أما التعليمة الثانية فتعاود تفعيلها. ويمكننا استعمال هذه الطريقة لتجميد/تثبيت عناصر أخرى أيضا، ليس العنصر <code>document.body</code> فقط.
</p>

<p>
	غير أن لهذه الدالّة نقطة سلبية، حيث يختفي شريط التمرير تماما بعد مناداتها، وبما أنه كان يشغل مساحة ما من الصفحة، فعند اختفائه، يتحرك محتوى الصفحة بعض الشيء لملء الفراغ الذي نتج عن اختفاء شريط التمرير. يبدو هذا غريبا بعض الشئ، ولكن يمكننا تفادي حدوث ذلك بموازنة قيمة الخاصية <code>clientWidth</code> قبل وبعد التثبيط، فإذا ازداد العرض بعد اختفاء شريط التمرير، نضيف حاشية <code>padding</code> للعنصر<code>document.body</code> مكان شريط التمرير للإبقاء على عرض محتوى الصفحة كما هو.
</p>

<h2>
	الخلاصة
</h2>

<ul>
<li>
		لمعرفة طول/عرض الجزء الظاهر من الصفحة (طول/عرض مساحة المحتوى) نستعمل الخاصيتين <code>document.documentElement.clientWidth/Height</code>. *لمعرفة الطول/العرض الكلي للصفحة بما فيها الجزء غير الظاهر في النافذة نبحث عن أكبر قيمة من بين القيم التالية:
	</li>
</ul>
<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7112_15" style="">
<span class="pln">let scrollHeight </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">max</span><span class="pun">(</span><span class="pln">
  document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">scrollHeight</span><span class="pun">,</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">documentElement</span><span class="pun">.</span><span class="pln">scrollHeight</span><span class="pun">,</span><span class="pln">
  document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">offsetHeight</span><span class="pun">,</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">documentElement</span><span class="pun">.</span><span class="pln">offsetHeight</span><span class="pun">,</span><span class="pln">
  document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">clientHeight</span><span class="pun">,</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">documentElement</span><span class="pun">.</span><span class="pln">clientHeight
</span><span class="pun">);</span></pre>

<ul>
<li>
		لقراءة إحداثيات موضع الجزء الظاهر من الصفحة إنطلاقا من الركن العلوي الأيسر للصفحة نستعمل الخاصيتين <code>window.pageYOffset/pageXOffset</code>.
	</li>
	<li>
		ولتغيير الموضع الحالي للنافذة نستعمل الدوالّ التالية:
		<ul>
<li>
				<code>window.scrollTo(pageX,pageY)</code>: التحريك نحو الموضع ذي الإحداثيات المطلقة (pageX,pageY).
			</li>
			<li>
				<code>window.scrollBy(x,y)</code> : التحريك بمقدار (x,y) انطلاقا من الموضع الحالي.
			</li>
			<li>
				<code>elem.scrollIntoView(top)</code>: التحريك لجعل العنصر <code>elem</code> ظاهرًا، أي تحريكه بحيث يتطابق مع أعلى أو أسفل النافذة حسب قيمة الوسيط <code>top</code>.
			</li>
		</ul>
</li>
</ul>
<p>
	ترجمة -وبتصرف- للفصل <a href="https://javascript.info/size-and-scroll-window" rel="external nofollow">Window sizes and scrolling</a> من كتاب <a href="https://javascript.info/ui" rel="external nofollow">Browser: Document, Events, Interfaces</a>
</p>
]]></description><guid isPermaLink="false">1120</guid><pubDate>Fri, 29 Jan 2021 13:02:42 +0000</pubDate></item><item><title>&#x627;&#x644;&#x62A;&#x62D;&#x643;&#x645; &#x641;&#x64A; &#x645;&#x642;&#x627;&#x633; &#x639;&#x646;&#x627;&#x635;&#x631; &#x635;&#x641;&#x62D;&#x629; HTML &#x648;&#x639;&#x645;&#x644;&#x64A;&#x629; &#x62A;&#x645;&#x631;&#x64A;&#x631; &#x627;&#x644;&#x635;&#x641;&#x62D;&#x629; (scrolling) &#x639;&#x628;&#x631; &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A;</title><link>https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%AA%D8%AD%D9%83%D9%85-%D9%81%D9%8A-%D9%85%D9%82%D8%A7%D8%B3-%D8%B9%D9%86%D8%A7%D8%B5%D8%B1-%D8%B5%D9%81%D8%AD%D8%A9-html-%D9%88%D8%B9%D9%85%D9%84%D9%8A%D8%A9-%D8%AA%D9%85%D8%B1%D9%8A%D8%B1-%D8%A7%D9%84%D8%B5%D9%81%D8%AD%D8%A9-scrolling-%D8%B9%D8%A8%D8%B1-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r1119/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_01/601403012faeb_--(size)---(scrolling).png.3daff043ba0ec0c4c2dbb086e27355cb.png" /></p>

<p>
	تضم جافاسكربت العديد من الخاصيات التي تسمح بقراءة معلومات طول عنصر ما (height)، وعرضه (width) وجوانب أخرى متعلقة بهندسته (geometry). هي معلومات نحتاجها عادة متى ما أردنا تحريك أو وضع عناصر ما على صفحة ويب باستعمال لغة جافاسكربت.
</p>

<h2>
	العنصر النموذجي
</h2>

<p>
	نستعين فيما يلي بالعنصر النموذجي التالي من أجل عرض الخاصيات:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6759_7" style="">
<span class="pln"> </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"example"</span><span class="tag">&gt;</span><span class="pln">
  ...Text...
</span><span class="tag">&lt;/div&gt;</span><span class="pln">
</span><span class="tag">&lt;style&gt;</span><span class="pln">
  </span><span class="com">#example {</span><span class="pln">
    width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">300px</span><span class="pun">;</span><span class="pln">
    height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">200px</span><span class="pun">;</span><span class="pln">
    border</span><span class="pun">:</span><span class="pln"> </span><span class="lit">25px</span><span class="pln"> solid </span><span class="com">#E8C48F;</span><span class="pln">
    padding</span><span class="pun">:</span><span class="pln"> </span><span class="lit">20px</span><span class="pun">;</span><span class="pln">
    overflow</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">auto</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="tag">&lt;/style&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" src="https://codepen.io/Hsoub/embed/BaQBvjb?height=265&amp;theme-id=light&amp;default-tab=html,result" style="width: 100%;" title="JS-p2-09-Element size and scrolling-ex1">See the Pen JS-p2-09-Element size and scrolling-ex1 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	يملك هذا العنصر إطارًا (<code>border</code>)، وحاشية (<code>padding</code>) وإحداثيات تمرير (<code>scrolling</code>)؛ أي مجموعة كاملة من الخاصيات. في حين أنه لا يملك هوامش (<code>margins</code>) لأنها لا تُعدّ جزءًا منه وليست لها خاصيات. ويبدو العنصر على الشكل التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2021_01/001sampleElement.png.3058c3489b4da59cd921e6aa2cf16f30.png" data-fileid="56613" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="56613" data-unique="4w6xhimpp" src="https://academy.hsoub.com/uploads/monthly_2021_01/001sampleElement.png.3058c3489b4da59cd921e6aa2cf16f30.png" alt="001sampleElement.png"></a>
</p>

<p>
	يمكنك الاطلاع على الشيفرة ومعاينتها على هذا <a href="https://plnkr.co/edit/79q3ufWDJVxYnGfE?p=preview&amp;preview" rel="external nofollow">الرابط</a>.
</p>

<p>
	<strong>ملاحظة: شريط التمرير</strong>
</p>

<p>
	تُظهر الصورة السابقة أكثر الحالات تعقيدًا، أي حين يكون للعنصر شريط تمرير،حيث تُخصِص بعض المتصفحات ( وليس كلّها) مساحةً لشريط التمرير من المساحة المخصصة للمحتوى، والمؤشَّر عليها في الصورة بعبارة 'عرض المحتوى' (content width). وبذلك يكون عرض المحتوى هنا <code>300 بكسل</code> في حالة عدم وجود شريط تمرير. ولكن شَغلَ شريط التمرير لمساحةٍ عرضها <code>16 بكسل</code> (يتغيّر هذا العرض من متصفح لآخر ومن جهاز لآخر) يُصغِّر من عرض المحتوى ليصبح <code>300-16=284 بكسل</code>. وعليه فإنه من الأهمية بمكان أخذ ذلك في الحسبان.
</p>

<p>
	يُسهِّل عدم وجود شريط التمرير العمليات الحسابية، ولكننا نفترض في الأمثلة الخاصة بهذا الفصل أنه موجود.
</p>

<p>
	<strong>ملاحظة: يمكن لمساحة الحاشية السفلى <code>padding-bottom</code> أن تحتوي نصا</strong>
</p>

<p>
	عادة ما تَظهر الحواشي فارغةً من أي محتوى. غير أن نص العنصر قد يكون طويلا جدًا بحيث لا تسعه مساحة المحتوى كاملا، فتُظهِره المتصفحات عادة في الحاشية السفلى للعنصر.
</p>

<h2>
	الخاصيات الهندسية لعنصر ما
</h2>

<p>
	فيما يلي صورة شاملة تُظهِر الخاصيات الهندسية لعنصر ما.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2021_01/002geometryProperties.png.69b9daecc81de211507e770f3782a324.png" data-fileid="56614" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="56614" data-unique="lce5sjkvy" src="https://academy.hsoub.com/uploads/monthly_2021_01/002geometryProperties.thumb.png.e98dca732225f45b5856ca826014f67b.png" alt="002geometryProperties.png"></a>
</p>

<p>
	تكون قيم هذه الخاصيات عبارة عن أرقام، ولكنها تُمثِّل في الحقيقة عدد البكسلات، فهي إذا مقاسات بالبكسل. فلنستعرض هذه الخاصيات إنطلاقًا من خارج العنصر نحو داخله.
</p>

<h2>
	الخاصيات offsetParent وoffsetLeft وoffsetTop
</h2>

<p>
	نادرًا ما نحتاج إلى هذه الخاصيات ولكنها تصف العنصر من الخارج ، لذا سنبدأ العرض بها:
</p>

<p>
	تمثل الخاصية <code>offsetParent</code> السلف الأقرب (<code>ancestor</code>) للعنصر ويستعملها المتصفح لحساب الإحداثيات أثناء ترجمة الشيفرات إلى صفحات ويب، ويكون السلف الأقرب إمّا:
</p>

<ol>
<li>
		متموضع باستعمال لغة CSS: يكون الموضع (<code>position</code>) إمّا مطلقا (<code>absolute</code>)، أو نسبي (<code>relative</code>)، أو ثابت (<code>fixed</code>) أو لاصق (<code>sticky</code>) أو،
	</li>
	<li>
		أحد العناصر: <code>&lt;td&gt;</code> ،<code>&lt;th&gt;</code> ،<code>&lt;table&gt;</code>، أو،
	</li>
	<li>
		العنصر <code>&lt;body&gt;</code>.
	</li>
</ol>
<p>
	وتعطي، في المثال التالي، الخاصيتان <code>offsetLeft</code> و<code>offsetTop</code> الإحداثيات <code>x</code> و<code>y</code> إنطلاقًا من الركن الأيسر العلوي للسلف الأقرب <code>offsetParent</code>. ويُعدّ العنصر <code>&lt;main&gt;</code> السلف الأقرب <code>offsetParent</code> للعنصر <code>&lt;div&gt;</code> المحصور داخله، وتحسب الخاصيتان <code>offsetLeft</code> و<code>offsetTop</code> إنطلاقًا من الركن العلوي الأيسر للعنصر <code>&lt;main&gt;</code>:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6759_9" style="">
<span class="pln"> </span><span class="tag">&lt;main</span><span class="pln"> </span><span class="atn">style</span><span class="pun">=</span><span class="atv">"</span><span class="pln">position</span><span class="pun">:</span><span class="pln"> relative</span><span class="atv">"</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"main"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;article&gt;</span><span class="pln">
    </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"example"</span><span class="pln"> </span><span class="atn">style</span><span class="pun">=</span><span class="atv">"</span><span class="pln">position</span><span class="pun">:</span><span class="pln"> absolute</span><span class="pun">;</span><span class="pln"> left</span><span class="pun">:</span><span class="pln"> </span><span class="lit">180px</span><span class="pun">;</span><span class="pln"> top</span><span class="pun">:</span><span class="pln"> </span><span class="lit">180px</span><span class="atv">"</span><span class="tag">&gt;</span><span class="pln">...</span><span class="tag">&lt;/div&gt;</span><span class="pln">
  </span><span class="tag">&lt;/article&gt;</span><span class="pln">
</span><span class="tag">&lt;/main&gt;</span><span class="pln">
</span><span class="tag">&lt;script&gt;</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln">example</span><span class="pun">.</span><span class="pln">offsetParent</span><span class="pun">.</span><span class="pln">id</span><span class="pun">);</span><span class="pln"> </span><span class="com">// main</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln">example</span><span class="pun">.</span><span class="pln">offsetLeft</span><span class="pun">);</span><span class="pln"> </span><span class="com">// 180 (*)</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln">example</span><span class="pun">.</span><span class="pln">offsetTop</span><span class="pun">);</span><span class="pln"> </span><span class="com">// 180</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" src="https://codepen.io/Hsoub/embed/preview/abBoPNw?height=265&amp;theme-id=light&amp;default-tab=html,result" style="width: 100%;" title="JS-p2-09-Element size and scrolling-ex2">See the Pen JS-p2-09-Element size and scrolling-ex2 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2021_01/003mostOuterGeometryProperties.png.43236174b67c6899966c9dc2e1e436fe.png" data-fileid="56615" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="56615" data-unique="q7zlgtli5" src="https://academy.hsoub.com/uploads/monthly_2021_01/003mostOuterGeometryProperties.png.43236174b67c6899966c9dc2e1e436fe.png" alt="003mostOuterGeometryProperties.png"></a>
</p>

<p>
	(*): لاحظ أن القيمة هنا عبارة عن رقم (180) وليس سلسلة نصية “180px”.
</p>

<p>
	هناك عدة حالات تحمل فيها الخاصية <code>offsetParent</code> القيمة <code>null</code>:
</p>

<ol>
<li>
		إذا كان العنصر غير ظاهر (<code>display:none</code> أو غير ظاهرٍ في الصفحة)
	</li>
	<li>
		إذا كان العنصر هو <code>&lt;body&gt;</code> أو <code>&lt;html&gt;</code>،
	</li>
	<li>
		إذا كان موضع العنصر يحمل القيمة <code>position:fixed</code>.
	</li>
</ol>
<h2>
	offsetWidth وoffsetHeight
</h2>

<p>
	نباشر الآن في عرض خاصيات العنصر نفسه. تُعدّ الخاصيتان <code>offsetHeight</code> و<code>offsetWidth</code> أبسط الخاصيات، حيث تعطيان الطول والعرض الخارجي الكلي للعنصر، بما في ذلك الأطر.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2021_01/004offsetWidthHeight.png.341af71a8286e9574bc9e73678a4196a.png" data-fileid="56616" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="56616" data-unique="dzflqswoh" src="https://academy.hsoub.com/uploads/monthly_2021_01/004offsetWidthHeight.png.341af71a8286e9574bc9e73678a4196a.png" alt="004offsetWidthHeight.png"></a>
</p>

<p>
	وفيما يتعلّق بالعنصر النموذجي لدينا:
</p>

<ul>
<li>
		<code>offsetWidth = 390</code>: العرض الكلي ويمكن حسابه بجمع العرض الداخلي المحدَّد في شيفرة CSS (أي 300 بكسل)، والحاشيتين (2<em>20 بكسل) و الإطارين (2</em>25 بكسل).
	</li>
	<li>
		<code>offsetHeight = 290</code>: الطول الخارجي.
	</li>
</ul>
<p>
	<strong>ملاحظة: تأخذ الخاصيات الهندسية للعناصر غير الظاهرة على الصفحة إحدى القيمتان 0 أو null</strong>
</p>

<p>
	لا تُحسب الخاصيات الهندسية إلا إذا تعلّق الأمر بعناصر ظاهرة على الصفحة. إذا كان العنصر أو أيًا من أسلافه يملك الخاصية <code>display:none</code> أو لم يكن ظاهرًا في الصفحة، تكون قيم كل الخاصيات الهندسية الخاصة به معدومة ( أو <code>null</code>، إذا تحدثنا عن الخاصية <code>offsetParent</code>).
</p>

<p>
	فعلى سبيل المثال، تحمل الخاصية <code>offsetParent</code> القيمة <code>null</code>، والخاصيتان <code>offsetWidth</code> و<code>offsetHeight</code> القيمة <code>0</code> إذا أنشأنا عنصرًا ما ولم نُضفه إلى الصفحة أو إذا كانت الخاصية <code>display</code> الخاصة به أو بأسلافه محدّدة بقيمة <code>none</code>. ويمكن التحقّق ممّا إذا كان العنصر ظاهرًا أو مخفيًا كالآتي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6759_11" style="">
<span class="pln"> </span><span class="kwd">function</span><span class="pln"> isHidden</span><span class="pun">(</span><span class="pln">elem</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">!</span><span class="pln">elem</span><span class="pun">.</span><span class="pln">offsetWidth </span><span class="pun">&amp;&amp;</span><span class="pln"> </span><span class="pun">!</span><span class="pln">elem</span><span class="pun">.</span><span class="pln">offsetHeight</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لاحظ هنا أن الدالّة <code>isHidden</code> تعيد القيمة <code>true</code> أيضًا إذا كان العنصر ظاهرًا على الصفحة ولكن مقاساته منعدمة، كالعنصر <code>&lt;div&gt;</code> مثلا إذا كان فارغًا.
</p>

<h2>
	clientTop وclientLeft
</h2>

<p>
	داخل العنصر، توجد الأطر، ولقياسها لدينا الخاصيتان <code>clientTop</code> و<code>clientLeft</code>، حيث تكون قيم كلُّ من الخاصيتين في المثال السابق كالآتي:
</p>

<ul>
<li>
		<code>clientLeft = 25</code>، عرض الإطار الأيسر.
	</li>
	<li>
		<code>clientTop = 25</code>، عرض الإطار العلوي.
	</li>
</ul>
<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2021_01/005clientLeftTop.png.527881a1a827d240f4313c79c846c22a.png" data-fileid="56617" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="56617" data-unique="8uv1o67jg" src="https://academy.hsoub.com/uploads/monthly_2021_01/005clientLeftTop.png.527881a1a827d240f4313c79c846c22a.png" alt="005clientLeftTop.png"></a>
</p>

<p>
	وحتى نكون دقيقين علينا أن ننبّه لأمر ما، وهو أن هاتين الخاصيتين لا تمثلان طول وعرض الإطار، بل الإحداثيات النسبية للجانب الداخلي إنطلاقًا من الجانب الخارجي.
</p>

<p>
	ما الفرق بينهما؟ يَظهر الفرق عندما يكون اتجاه الصفحة من اليمين إلى اليسار (إذا كانت لغة المتصفح هي العربية أو العبرية)، حيث يَظهر شريط التمرير في هذه الحالة على الجهة اليسرى بدل اليمنى، وبذلك تضم الخاصية <code>clientLeft</code> عرض شريط التمرير أيضا. وهنا لا تكون قيمة الخاصية <code>clientLeft</code> هي 25، بل 25 زائد عرض شريط التمرير (25 + 16 = 41) . وفيما يلي مثال باللغة العبرية:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2021_01/006clientLeftTopHebrew.png.f3aca790dd5fbe98769cd0dc75dbd606.png" data-fileid="56618" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="56618" data-unique="2fb1ofra9" src="https://academy.hsoub.com/uploads/monthly_2021_01/006clientLeftTopHebrew.png.f3aca790dd5fbe98769cd0dc75dbd606.png" alt="006clientLeftTopHebrew.png"></a>
</p>

<h2>
	clientWidth وclientHeight
</h2>

<p>
	تعطي هاتان الخاصيتان مقاسات المساحة المحصورة بين إطاري العنصر، وتضمّان عرض المحتوى بما فيه الحاشيتين، ولكن دون عرض شريط التمرير.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2021_01/007clientWidthHeight.png.bfbd19809d8595e465b6644bd7534eb0.png" data-fileid="56619" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="56619" data-unique="mt52lg81q" src="https://academy.hsoub.com/uploads/monthly_2021_01/007clientWidthHeight.png.bfbd19809d8595e465b6644bd7534eb0.png" alt="007clientWidthHeight.png"></a>
</p>

<p>
	فلنتحدث أولا عن الخاصية <code>clientHeight</code> المذكورة في الصورة أعلاه. لا وجود في الصورة لشريط تمرير أفقي، فقيمتها إذًا تساوي بالتدقيق مجموع ماهو محصور بين الإطارين، أي الطول المحدَّد في شيفرة CSS (أي 200 بكسل) زائد الحاشيتين السفلية والعلوية (2*20 بكسل) وهو ما يعطي القيمة 240 بكسل. أما بالنسبة للخاصية <code>clientWidth</code>، فلا يساوي عرض المحتوى 300 بكسل، بل 240 بكسل، ذلك لأن شريط التمرير يشغَل مساحةً عرضها 16 بكسل. فالنتيجة تكون 284 بكسل زائد عرض الحاشيتين اليمنى واليسرى. المجموع إذا 324 بكسل. وفي حالة عدم وجود الحاشيتين تساوي قيمة الخاصيتين <code>clientWidth</code> و<code>clientHeight</code> بالتدقيق عرض وطول مساحة المحتوى المحصورة بين الأطر وشريط التمرير إن وجد.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2021_01/008ClientWidthHeightWithoutPaddings.png.7ce4226b13e8a5c4be0a98ddcd6d9d0e.png" data-fileid="56620" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="56620" data-unique="m9r4kxdyh" src="https://academy.hsoub.com/uploads/monthly_2021_01/008ClientWidthHeightWithoutPaddings.png.7ce4226b13e8a5c4be0a98ddcd6d9d0e.png" alt="008ClientWidthHeightWithoutPaddings.png"></a>
</p>

<p>
	يمكننا إذا استعمال الخاصيتين <code>clientWidth</code> و<code>clientHeight</code> للحصول على مقاسات مساحة المحتوى إن لم يكن للعنصر حواشي.
</p>

<h2>
	scrollWidth وscrollHeight
</h2>

<p>
	تشبه هاتان الخاصيتان الخاصيتين <code>clientWidth</code> و<code>clientHeight</code>، ولكنهما تضمان أيضًا الأجزاء غير الظاهرة.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2021_01/009scrollWidthHeight.png.649ed7e70373c13300359e28ced69af6.png" data-fileid="56621" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="56621" data-unique="mewdsmrre" src="https://academy.hsoub.com/uploads/monthly_2021_01/009scrollWidthHeight.png.649ed7e70373c13300359e28ced69af6.png" alt="009scrollWidthHeight.png"></a>
</p>

<p>
	لدينا في الصورة أعلاه:
</p>

<ul>
<li>
		<code>scrollHeight = 723</code>، وتمثل الطول الداخلي الكلي لمساحة المحتوى بما فيه الأجزاء غير الظاهرة.
	</li>
	<li>
		<code>scrollWidth = 324</code>، وتمثل العرض الداخلي الكلي، وبما أنه لا وجود لشريط تمرير أفقي، فهي تساوي <code>clientWidth</code>.
	</li>
</ul>
<p>
	ويمكننا استخدام هاتين الخاصيتين لتوسيع العنصر إلى طوله أو عرضه الكلي كالآتي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6759_13" style="">
<span class="com">// توسيع محتوى العنصر إلى طوله الكلي</span><span class="pln">
element</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">height </span><span class="pun">=</span><span class="pln"> </span><span class="pun">`</span><span class="pln">$</span><span class="pun">{</span><span class="pln">element</span><span class="pun">.</span><span class="pln">scrollHeight</span><span class="pun">}</span><span class="pln">px</span><span class="pun">`;</span><span class="pln"> </span></pre>

<p>
	حيث يختفي هنا شريط التمرير، ويظهر محتوى العنصر كاملا.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2021_01/010beforeExpand.png.95d702b15490b80994cbadbe25d8bcaf.png" data-fileid="56622" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="56622" data-unique="5jax5nyhq" src="https://academy.hsoub.com/uploads/monthly_2021_01/010beforeExpand.png.95d702b15490b80994cbadbe25d8bcaf.png" alt="010beforeExpand.png"></a>
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2021_01/011afterExpand.png.7ede2704b822439917f61479fc3dcfe4.png" data-fileid="56623" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="56623" data-unique="ve0aug6ns" src="https://academy.hsoub.com/uploads/monthly_2021_01/011afterExpand.png.7ede2704b822439917f61479fc3dcfe4.png" alt="011afterExpand.png"></a>
</p>

<h2>
	scrollLeft وscrollTop
</h2>

<p>
	تمثل الخاصيتان <code>scrollLeft</code> و<code>scrollTop</code> عرض وطول الجزء غير الظاهر من العنصر (الذي جرى المُرور عليه). لاحظ في الصورة الموالية الخاصيتين <code>scrollHeight</code> و<code>scrollTop</code> لمقطع يضم شريط تمرير عمودي.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2021_01/012scrollTopLeft.png.603ffd81218a5aec08b2337c44719d94.png" data-fileid="56624" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="56624" data-unique="x1nrrw4pu" src="https://academy.hsoub.com/uploads/monthly_2021_01/012scrollTopLeft.png.603ffd81218a5aec08b2337c44719d94.png" alt="012scrollTopLeft.png"></a>
</p>

<p>
	بعبارة أخرى، تمثل الخاصية <code>scrollTop</code> مقدار تمرير العنصر إنطلاقًا من أعلى الصفحة.
</p>

<p>
	<strong>ملاحظة: يمكن التعديل على الخاصيتين scrollLeft وscrollTop</strong>
</p>

<p>
	تُعدّ أغلب الخاصيات التي استعرضناها هنا قابلة للقراءة فقط (<code>read-only</code>)، ولكن الخاصيتين <code>scrollLeft</code> و<code>scrollTop</code> يمكن تغييرهما ليحرِّك المتصفح العنصر. إذا كان لدينا عنصرًا ما، وليكن <code>elem</code>، فإن التعليمة <code>elem.scrollTop += 10</code> تُحرِّكه بمقدار <code>10 بكسل</code> نحو الأسفل. ويؤدي إسناد القيمة <code>0</code> أو أيّ قيمةٍ كبيرةٍ جدًا (مثلا <code>1e9</code>) للخاصية <code>scrollTop</code> إلى تحريك العنصر إلى أقصى أعلى أو أسفل الصفحة.
</p>

<h2>
	لا تأخذ طول وعرض العنصر من شيفرة CSS
</h2>

<p>
	تحدثنا أعلاه عن الخاصيات الهندسية لعناصر DOM التي يمكن استخدامها للحصول على الطول والعرض ولحساب المسافات. وسبق لك وأن تعرفت في فصل الأنماط التنسيقية والأصناف، أنه يمكن قراءة الطول والعرض المحدَّدّين في شيفرة CSS لعنصر ما باستعمال الدالّة <code>getComputedStyle</code>، فلماذا لا نقرأ عرض عنصرٍ ما باستعمال الدالّة <code>getComputedStyle</code>، كما في المثال التالي؟
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6759_15" style="">
<span class="pln">let elem </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">;</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> getComputedStyle</span><span class="pun">(</span><span class="pln">elem</span><span class="pun">).</span><span class="pln">width </span><span class="pun">);</span><span class="pln"> </span><span class="com">// إظهار عرض العنصر المحدَّدّ في شيفرة CSS</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" src="https://codepen.io/Hsoub/embed/preview/yLVBGJe?height=265&amp;theme-id=light&amp;default-tab=js,result" style="width: 100%;" title="JS-p2-09-Element size and scrolling-ex3">See the Pen JS-p2-09-Element size and scrolling-ex3 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	لماذا عليك استعمال الخاصيات الهندسية بدلًا من هذه الدالّة؟ هناك سببان لذلك:
</p>

<ul>
<li>
		الأول، هو أن الطول والعرض المحدَّدين في شيفرة CSS يتعلّقان بخاصية أخرى وهي <code>box-sizing</code>، التي تحدِّد الطول والعرض في شيفرة CSS. ويمكن لأيّ تغيير في الخاصية <code>box-sizing</code> أن يوقِف عمل شيفرة جافاسكربت.
	</li>
	<li>
		والثاني، هو أن الطول والعرض المحدَّدين في شيفرة CSS، قد يحملان القيمة <code>"auto"</code> كما هو الحال بالنسبة للعناصر السطرية (inline element).
	</li>
</ul>
<p>
	مثال:
</p>

<pre class="ipsCode">
 &lt;span id="elem"&gt;Hello!&lt;/span&gt;
&lt;script&gt;
  alert( getComputedStyle(elem).width ); // auto
&lt;/script&gt;
</pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" src="https://codepen.io/Hsoub/embed/preview/JjbPwKr?height=265&amp;theme-id=light&amp;default-tab=html,result" style="width: 100%;" title="JS-p2-09-Element size and scrolling-ex4">See the Pen JS-p2-09-Element size and scrolling-ex4 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	يُعدّ إسناد القيمة <code>"auto"</code> للخاصية <code>width</code> أمرًا عاديًا جدًا في لغة CSS، ولكن جافاسكربت يتطلّب مقاسا دقيقا بالبكسل حتى يستخدمه في العمليات الحسابية. لذلك لن يفيدك العمل بالعرض المحدَّد في شيفرة CSS في هذه الحالة.
</p>

<p>
	هناك أيضا سببٌ آخر يتعلّق بشريط التمرير. حيث يحدث أن يعمل سكربت معين بصفة عادية إن لم يكن هناك شريط تمرير، في حين يُظهِر العديدَ من الأخطاء البرمجية في حالة وجوده. هذا لأن شريط التمرير يَشغَل مساحةً من المحتوى في بعض المتصفحات، فيكون العرض الحقيقي المتاح للمحتوى أقل من العرض الذي تحدِّده شيفرة CSS، وهو ما تأخذه الخاصيتان <code>clientWidth</code> و<code>clientHeight</code> في الحسبان.
</p>

<p>
	ولكن الأمر يختلف عند استخدام التعليمة <code>getComputedStyle(elem).width</code>، حيث تُعيد بعض المتصفحات (مثل المتصفح Chrome) العرض الداخلي الحقيقي بعد طرح عرض شريط التمرير منه، وتُعيد بعض المتصفحات الأخرى (مثل المتصفح Firefox) العرض المحدَّد في شيفرة CSS (حيث يُهمِل هذا المتصفح شريط التمرير). ويُعدّ هذا الاختلاف من متصفح لآخر هو السبب الذي يحمِلنا على عدم استعمال الدالّة <code>getComputedStyle</code> بل الاعتماد على الخاصيات الهندسية بدلا منها.
</p>

<p>
	وإذا كان المتصفح المثبَّت على حاسوبك يُخصِص مساحةً لشريط التمرير (وهو ما تُوفره معظم متصفحات نظام التشغيل Windows) ، يمكنك معاينة السكربت من خلال هذا <a href="https://en.js.cx/article/size-and-scroll/cssWidthScroll" rel="external nofollow">الرابط</a>
</p>

<p>
	هنا، يساوي عرض العنصر المحدَّد في شيفرة CSS الذي يضم النص 300 بكسل.
</p>

<p>
	تُخصِص المتصفحات Chrome وFirefox وEdge على نظام التشغيل Windows المكتبي مساحةً لشريط التمرير. ولكن المتصفح Firefox يُظهر القيمة 300 بكسل، في حين يُظهر المتصفح Chrome والمتصفح Edge قيمةً أقل، لأن المتصفح Firefox يُظهر العرض المحدَّد في شيفرة CSS، أمّا بقية المتصفحات فتُعيد العرض الحقيقي للعنصر (بعد اقتطاع عرض شريط التمرير). لاحظ أن الفرق يظهر فقط عند قراءة القيمة باستعمال الدالّة <code>getComputedStyle(...).width</code> في شيفرة جافاسكربت، حيث يكون الشكل الذي يَظهر على الشاشة صحيحًا.
</p>

<h2>
	الخلاصة
</h2>

<p>
	تملك العناصر الخاصيات الهندسية التالية:
</p>

<ul>
<li>
		<code>offsetParent</code>: تمثل السلف الأقرب للعنصر من حيث التموضع أو إحدى القيم التالية: <code>td</code> أو <code>th</code> أو<code>table</code> أو<code>body</code>.
	</li>
	<li>
		<code>offsetLeft</code> و<code>offsetTop</code>: تمثل إحداثيات العنصر إنطلاقًا من الحافة العلوية اليسرى للعنصر السلف <code>offsetParent</code> الخاص به.
	</li>
	<li>
		<code>offsetWidth</code> و<code>offsetHeight</code>: تمثل العرض والطول الخارجي لعنصر ما بما فيه الأطر.
	</li>
	<li>
		<code>clientLeft</code> و<code>clientTop</code>: تمثلان المسافتين بين الركن العلوي الأيسر الخارجي والركن العلوي الأيسر الداخلي (المحتوى + الحاشية). بالنسبة لأنظمة التشغيل التي تعمل باللّغات التي تُكتَب من اليسار إلى اليمين، تساوي هاتان الخاصيتان عرض الإطارين العلوي والأيسر، أما بالنسبة لأنظمة التشغيل التي تعمل باللّغات التي تُكتَب من اليمين إلى اليسار، يكون شريط التمرير من الجهة اليسرى، وبذلك تضم الخاصية <code>clientLeft</code> عرض شريط التمرير أيضًا.
	</li>
	<li>
		<code>clientWidth</code> و<code>clientHeight</code>: تمثلان عرض وطول المحتوى بما فيه الحواشي دون احتساب عرض شريط التمرير.
	</li>
	<li>
		<code>scrollWidth</code> و<code>scrollHeight</code>: تمثلان عرض وطول المحتوى، تماما مثل ما هو الحال بالنسبة للخاصيتين <code>clientWidth</code> و<code>clientHeight</code>، ولكن مع احتساب الأجزاء غير الظاهرة من العنصر.
	</li>
	<li>
		<code>scrollLeft</code> و<code>scrollTop</code>: تمثل عرض وطول الجزء العلوي للعنصر الذي جرى المُرور عليه إنطلاقًا من الركن العلوي الأيسر للعنصر.
	</li>
</ul>
<p>
	وتُعد كلّ هذه الخاصيات قابلة للقراءة فقط (<code>read-only</code>) عدا الخاصيتين <code>scrollLeft</code> و<code>scrollTop</code> اللّتين يؤدي تغيير قيمتهما إلى تحريك المتصفح للعنصر.
</p>

<h2>
	تمارين
</h2>

<h3>
	مقاس الجزء الذي لم نمر عليه بعد
</h3>

<p>
	<em>درجة الأهمية: 5</em> تمثل الخاصية <code>elem.scrollTop</code> مقاس الجزء الذي جرى المُرور عليه إنطلاقًا من الأعلى. كيف يمكننا إذًا الحصول على مقاس الجزء الذي لم نمر عليه بعد (ولنسمه <code>scrollBottom</code>)؟
</p>

<p>
	اكتب الشيفرة التي تسمح بالحصول على مقاس الجزء (من عنصر ما) الذي لم نمر عليه بعد، وليكن هذا العنصر <code>elem</code>.
</p>

<p>
	<strong>ملاحظة</strong>: عليك التحقّق من الشيفرة التي تكتبها، حيث ينبغي أن تعطي القيمة <code>0</code> إذا لم يكن هناك شريط تمرير، أو إذا كان العنصر متموضعًا أساسا في الأسفل.
</p>

<h4>
	<strong>الحل</strong>
</h4>

<p>
	الحل هو كالآتي:
</p>

<pre class="ipsCode">
 let scrollBottom = elem.scrollHeight - elem.scrollTop - elem.clientHeight;
</pre>

<p>
	أو بعبارة أخرى، (الطول الكلي) ناقص (الجزء العلوي الذي جرى المُرور عليه) ناقص (الجزء الظاهر). هذا ما يسمح بالحصول على الجزء الذي لم نمر عليه بعد.
</p>

<h3>
	ما هو عرض شريط التمرير؟
</h3>

<p>
	_درجة الأهمية: _3
</p>

<p>
	اكتب الشيفرة التي تُعيد عرض شريط تمرير عادي. يكون هذا العرض بالنسبة لنظام التشغيل Windows بين 12 و20 بكسل. وفي حالة ما لم يُخصِص المتصفح مساحةَ لشريط التمرير (يحدث أن يكون الشريط نصف شفاف ويتموضع فوق النص)، يكون عرضه منعدما.
</p>

<p>
	<strong>ملاحظة</strong>: ينبغي أن تعمل الشيفرة على أيّ صفحة HTML كانت وأن لا تكون مرتبطة بمحتوى هذه الصفحة.
</p>

<h4>
	<strong>الحل</strong>
</h4>

<p>
	للحصول على عرض شريط التمرير، يمكن إنشاء عنصرٍ يملك شريط تمرير لكن دون أطر ولا حواشي. وبذلك يكون الفرق بين العرض الكلي للعنصر <code>offsetWidth</code> وعرض المساحة الداخلية للمحتوى <code>clientWidth</code> هو عرض شريط التمرير.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6759_17" style="">
<span class="pln"> </span><span class="com">// إنشاء حاوية تملك شريط تمرير</span><span class="pln">
let div </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">createElement</span><span class="pun">(</span><span class="str">'div'</span><span class="pun">);</span><span class="pln">
div</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">overflowY </span><span class="pun">=</span><span class="pln"> </span><span class="str">'scroll'</span><span class="pun">;</span><span class="pln">
div</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">width </span><span class="pun">=</span><span class="pln"> </span><span class="str">'50px'</span><span class="pun">;</span><span class="pln">
div</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">height </span><span class="pun">=</span><span class="pln"> </span><span class="str">'50px'</span><span class="pun">;</span><span class="pln">
</span><span class="com">// إضافتها للصفحة، وإلا فسوف نحصل على مقاسات منعدمة (0  بكسل)</span><span class="pln">
document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">append</span><span class="pun">(</span><span class="pln">div</span><span class="pun">);</span><span class="pln">
let scrollWidth </span><span class="pun">=</span><span class="pln"> div</span><span class="pun">.</span><span class="pln">offsetWidth </span><span class="pun">-</span><span class="pln"> div</span><span class="pun">.</span><span class="pln">clientWidth</span><span class="pun">;</span><span class="pln">
div</span><span class="pun">.</span><span class="pln">remove</span><span class="pun">();</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">scrollWidth</span><span class="pun">);</span></pre>

<h3>
	وضع الكرة في مركز المساحة الخضراء
</h3>

<p>
	<em>درجة الأهمية: 5</em>
</p>

<p>
	تكون الصفحة مبدئيا كالآتي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2021_01/013ballSourceDocument.png.15447125ac5a4e809fa498b9021bca6d.png" data-fileid="56625" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="56625" data-unique="6qyjczzqc" src="https://academy.hsoub.com/uploads/monthly_2021_01/013ballSourceDocument.png.15447125ac5a4e809fa498b9021bca6d.png" alt="013ballSourceDocument.png"></a>
</p>

<p>
	ما هي إحداثيات مركز المساحة الخضراء؟
</p>

<p>
	احسبها واتبِّع ما يلي لوضع الكرة في مركز المساحة الخضراء:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2021_01/014ballSolutionDocument.png.fb091d075a209b68ebece00047fa3fb6.png" data-fileid="56626" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="56626" data-unique="m2zepvmzl" src="https://academy.hsoub.com/uploads/monthly_2021_01/014ballSolutionDocument.png.fb091d075a209b68ebece00047fa3fb6.png" alt="014ballSolutionDocument.png"></a>
</p>

<ul>
<li>
		حرِّك العنصر باستعمال لغة جافاسكربت، وليس لغة CSS.
	</li>
	<li>
		ينبغي أن تعمل الشيفرة مهما كان مقاس الكرة ومهما كان مقاس المساحة الخضراء وليس فقط مع المقاسات المعطاة.
	</li>
</ul>
<p>
	<strong>ملاحظة</strong>: يمكن وضع الكرة في المركز باستعمال لغة CSS، ولكننا نريد تجسيد ذلك باستعمال لغة جافاسكربت. سوف تُصادف مستقبلا مواضيع أخرى ووضعيات أكثر تعقيدًا، حيث يكون استعمال جافاسكربت ضرورة حتمية. يُعدّ هذا المثال مجرّد تمرين بسيط للتسخين.
</p>

<p>
	يمكنك الاطلاع على شيفرة التمرين من <a href="https://plnkr.co/edit/xkru9S3bh1Ihfr9y?p=preview&amp;preview" rel="external nofollow">هنا</a>
</p>

<h4>
	<strong>الحل</strong>
</h4>

<p>
	موضع الكرة هو <code>position:absolute</code>، وهو ما يعني أن إحداثياتها بالنسبة للأعلى ولليسار تُحسب بناءً على أقرب عنصر متموضع، أي العنصر <code>‎#field</code> (لأنه يملك الموضع <code>position:relative</code>). يكون مبدأ الإحداثيات (0،0) متطابقا مع الركن العلوي الأيسر الداخلي للمساحة الخضراء.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2021_01/015ballCoordinates.png.441498276ec68446a1431968cd27ce4a.png" data-fileid="56627" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="56627" data-unique="39tajh7ot" src="https://academy.hsoub.com/uploads/monthly_2021_01/015ballCoordinates.png.441498276ec68446a1431968cd27ce4a.png" alt="015ballCoordinates.png"></a>
</p>

<p>
	تُمثِل قيم الخاصيتين <code>clientWidth</code>و<code>clientHeight</code> العرض والطول الداخليين للمساحة الخضراء، وبالتالي تكون إحداثيات المركز كالآتي: (clientWidth/2, clientHeight/2). ولكننا حين نسند هذه القيم للخاصيتين <code>ball.style.left</code> و<code>ball.style.top</code> نجعل الحافة العلوية اليسرى للكرة، وليس الكرة بأكملها، تتحرك نحو المركز، فتظهر على هذا الشكل:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6759_20" style="">
<span class="pln">ball</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">left </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">round</span><span class="pun">(</span><span class="pln">field</span><span class="pun">.</span><span class="pln">clientWidth </span><span class="pun">/</span><span class="pln"> </span><span class="lit">2</span><span class="pun">)</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="str">'px'</span><span class="pun">;</span><span class="pln">
ball</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">top </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">round</span><span class="pun">(</span><span class="pln">field</span><span class="pun">.</span><span class="pln">clientHeight </span><span class="pun">/</span><span class="pln"> </span><span class="lit">2</span><span class="pun">)</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="str">'px'</span><span class="pun">;</span></pre>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2021_01/016ballCenterProblem.png.1b6d3da9dc0d33d7f4ea19bc923ba16a.png" data-fileid="56628" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="56628" data-unique="swzboros9" src="https://academy.hsoub.com/uploads/monthly_2021_01/016ballCenterProblem.png.1b6d3da9dc0d33d7f4ea19bc923ba16a.png" alt="016ballCenterProblem.png"></a>
</p>

<p>
	ومن أجل مطابقة مركز الكرة مع مركز المساحة الخضراء، ينبغي تحريك الكرة بمقدار نصف طولها للأعلى وبمقدار نصف عرضها نحو الجهة اليسرى. وبذلك تتموضع الكرة في مركز المساحة الخضراء.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6759_22" style="">
<span class="pln"> ball</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">left </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">round</span><span class="pun">(</span><span class="pln">field</span><span class="pun">.</span><span class="pln">clientWidth </span><span class="pun">/</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> ball</span><span class="pun">.</span><span class="pln">offsetWidth </span><span class="pun">/</span><span class="pln"> </span><span class="lit">2</span><span class="pun">)</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="str">'px'</span><span class="pun">;</span><span class="pln">
ball</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">top </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">round</span><span class="pun">(</span><span class="pln">field</span><span class="pun">.</span><span class="pln">clientHeight </span><span class="pun">/</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> ball</span><span class="pun">.</span><span class="pln">offsetHeight </span><span class="pun">/</span><span class="pln"> </span><span class="lit">2</span><span class="pun">)</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="str">'px'</span><span class="pun">;</span></pre>

<p>
	<em>تحذير</em> لا تعمل الشيفرة بالشكل المطلوب إذا لم يكن للكرة طول أو عرض.
</p>

<pre class="ipsCode">
 &lt;img src="ball.png" id="ball"&gt;
</pre>

<p>
	إذا لم يجد المتصفح طول وعرض صورةٍ ما ضمن سمات الوسوم أو في شيفرة CSS، يعتدّها منعدمة إلى غاية التحميل الكلي للصورة ، وبالتالي تكون قيمة <code>ball.offsetWidth</code> منعدمة إلى غاية تحميل الصورة بشكل كامل. وهذا ما ينتج عنه إحداثيات خاطئة عند استعمال الشيفرة أعلاه.
</p>

<p>
	بعد عملية التحميل الأولى للصورة، يضع المتصفح الصورة في الذاكرة المؤقتة (cache)، وعند إعادة التحميل، يحصل المتصفح على المقاسات في الحين. لكن المشكل هو أن قيمة الخاصية <code>ball.offsetWidth</code> تكون منعدمة عند عملية التحميل الأولى. يمكن تفادي حصول ذلك بإسناد قيمة للسمتين <code>width</code> و<code>height</code> الخاصتين بالصورة <code>&lt;img&gt;</code>:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6759_24" style="">
<span class="pln"> </span><span class="tag">&lt;img</span><span class="pln"> </span><span class="atn">src</span><span class="pun">=</span><span class="atv">"ball.png"</span><span class="pln"> </span><span class="atn">width</span><span class="pun">=</span><span class="atv">"40"</span><span class="pln"> </span><span class="atn">height</span><span class="pun">=</span><span class="atv">"40"</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"ball"</span><span class="tag">&gt;</span></pre>

<p>
	أو إضافة المقاسات في شيفرة CSS كالآتي:
</p>

<pre class="ipsCode prettyprint lang-css prettyprinted" id="ips_uid_6759_26" style="">
<span class="pln"> </span><span class="com">#ball {</span><span class="pln">
  width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">40px</span><span class="pun">;</span><span class="pln">
  height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">40px</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يمكنك الاطلاع على الحل من خلال هذا <a href="https://plnkr.co/edit/Tthd4Zdyvyxku03K?p=preview&amp;preview" rel="external nofollow">الرابط</a>
</p>

<h3>
	الفرق بين العرض المحدَّد في شيفرة CSS وclientWidth
</h3>

<p>
	<em>درجة الأهمية 5</em><br>
	ما هو الفرق بين <code>getComputedStyle(elem).width</code> و <code>elem.clientWidth</code>؟ أعط ثلاث فوارق على الأقل، ويستحسن أكثر.
</p>

<h4>
	<strong>الحل</strong>
</h4>

<p>
	الفوارق هي كالآتي:
</p>

<ol>
<li>
		تُعدّ قيمة الخاصية <code>clientWidth</code> قيمة عددية، بينما تكون قيمة <code>getComputedStyle(elem).width</code> عبارة عن سلسلة نصية تحمل في نهايتها الحرفين<code>px</code>.
	</li>
	<li>
		يمكن أن تُعيد الدالّة <code>getComputedStyle</code> قيمًا غير عددية كالقيمة <code>"auto"</code> مثلا بالنسبة للعناصر السطرية.
	</li>
	<li>
		تمثل الخاصية <code>clientWidth</code> مقاس المساحة الداخلية للمحتوى بالإضافة إلى الحواشي، بينما لا يضم العرض المحدَّد في شيفرة CSS (مع خاصية <code>box-sizing</code> عادية) الحواشي (يتمثل في مقاس المساحة الداخلية للمحتوى دون الحاشيتين).
	</li>
	<li>
		إذا كان هناك شريط تمرير وخَصص المتصفح مساحةً لهذا الشريط، قد تطرح بعض المتصفحات هذه المسافة من العرض المحدَّد في شيفرة CSS (لأنه لم يَعُد متاحا ليضم محتوى ما)، ولكن بعض المتصفحات الأخرى لا تسلك السلوك نفسه. أما الخاصية <code>clientWidth</code> فهي دائما تمثل نفس القيمة، حيث يُطرَح عرض شريط التمرير إذا خُصصت له مساحةً ما.
	</li>
</ol>
<p>
	ترجمة -وبتصرف- للفصل <a href="https://javascript.info/size-and-scroll" rel="external nofollow">Element size and scrolling</a> من كتاب <a href="https://javascript.info/ui" rel="external nofollow">Browser: Document, Events, Interfaces</a>
</p>
]]></description><guid isPermaLink="false">1119</guid><pubDate>Fri, 29 Jan 2021 12:50:02 +0000</pubDate></item><item><title>&#x643;&#x64A;&#x641;&#x64A;&#x629; &#x62A;&#x646;&#x633;&#x64A;&#x642; &#x639;&#x646;&#x627;&#x635;&#x631; &#x635;&#x641;&#x62D;&#x629; HTML &#x639;&#x628;&#x631; &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A;</title><link>https://academy.hsoub.com/programming/javascript/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%AA%D9%86%D8%B3%D9%8A%D9%82-%D8%B9%D9%86%D8%A7%D8%B5%D8%B1-%D8%B5%D9%81%D8%AD%D8%A9-html-%D8%B9%D8%A8%D8%B1-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r1118/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_01/6013fd985b1c4_--(styles)--(classes).png.d6871bab925869527ced958f058536e1.png" /></p>

<p>
	تجدر بنا الإشارة إلى قاعدة مهمة قبل الشروع في الحديث عن كيفية تعامل جافاسكربت مع الأنماط والأصناف. القاعدة بديهية جدًا ولكننا سنذكرها للإفادة. هناك طريقتان تُستخدمان لتنسيق عنصرٍ ما:
</p>

<ol>
<li>
		إنشاء صنف في ملف CSS وإضافته للعنصر على الشكل التالي: <code>&lt;div class="..."‎&gt;</code>
	</li>
	<li>
		كتابة خاصيات السمة <code>style</code> مباشرة بين تسلسلات التهريب الخاصة بالعنصر على الشكل التالي: <code>&lt;div style="..."‎&gt;</code>
	</li>
</ol>
<p>
	تستطيع لغة جافاسكربت التعديل على خاصيات الأصناف وخاصيات الخاصية <code>style</code>. ويُستحسن استعمال أصناف CSS للتنسيق بدلا من السمة <code>style</code>، حيث نلجأ إلى الطريقة الثانية فقط إذا تعذّرعلينا إضافة التنسيق باستعمال الطريقة الأولى.
</p>

<p>
	فعلى سبيل المثال، يمكن استعمال الخاصية <code>style</code> إذا كان عليك حساب إحداثيات عنصر ما ديناميكيًا وتحديد قيمها باستعمال جافاسكربت كالآتي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7651_7" style="">
<span class="pln">let top </span><span class="pun">=</span><span class="pln"> </span><span class="com">/* عمليات حسابية معقّدة */</span><span class="pun">;</span><span class="pln">
let left </span><span class="pun">=</span><span class="pln"> </span><span class="com">/* عمليات حسابية معقّدة */</span><span class="pun">;</span><span class="pln">
elem</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">left </span><span class="pun">=</span><span class="pln"> left</span><span class="pun">;</span><span class="pln"> </span><span class="com">// e.g '123px', تُحسب أثناء التنفيذ</span><span class="pln">
elem</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">top </span><span class="pun">=</span><span class="pln"> top</span><span class="pun">;</span><span class="pln"> </span><span class="com">// e.g '456px'</span></pre>

<p>
	وفي حالات أخرى مثل تلوين النص بالأحمر، أو إضافة صورة للخلفية، يُستحسن وصف التنسيق باستعمال CSS ثم إضافة الصنف للعنصر (يمكن عمل ذلك باستعمال جافاسكربت)، حيث يمنحك ذلك أكثر مرونة وسهولة في البرمجة.
</p>

<h2>
	اسم الصنف (className) وقائمة الأصناف (classList)
</h2>

<p>
	يُعدّ تعديل الصنف أكثر عمليةٍ نُصادفها في السكربتات. وكانت جافاسكربت فيما مضى تتّسمُ بالمحدودية حين يتعلّق الأمر بالكلمة المحجوزة <code>"class"</code>، حيث لم تكن تسمح بأن تحمل خاصيةٌ من خواص الكائن (object) اسم <code>"class"</code> كالآتي : <code>elem.class</code>. حينها جاء التفكير في استحداث خاصية مشابهة تسمى <code>"className"</code> تُطبّق على الأصناف. حيث يمثِّل <code>elem.className</code> اسم السمة <code>"class"</code> كما هو مبين في المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7651_9" style="">
<span class="tag">&lt;body</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"main page"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;script&gt;</span><span class="pln">
    alert</span><span class="pun">(</span><span class="pln">document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">className</span><span class="pun">);</span><span class="pln"> </span><span class="com">// main page</span><span class="pln">
  </span><span class="tag">&lt;/script&gt;</span><span class="pln">
</span><span class="tag">&lt;/body&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-08-Styles and classes-ex1" src="https://codepen.io/Hsoub/embed/preview/bGBbQJz?height=265&amp;theme-id=light&amp;default-tab=html,result">See the Pen JS-p2-08-Styles and classes-ex1 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	في حالة ما إذا أسندنا قيمةً معينةً للخاصية <code>elem.className</code>، تعوِّض هذه القيمة مُجمل سلسلة الأصناف. هذا ما نحتاج إليه أحيانا، ولكننا نحتاج في غالبية الحالات إلى إضافة أو حذف صنفٍ واحدٍ فقط. ولهذا وُجدت خاصية أخرى؛ إنها خاصية <code>elem.classList</code>. تُعدّ هذه الخاصية كائنًا خاصًا بحد ذاته له دوالّه الخاصة (methods) لإضافة صنف ما (<code>add</code>) أو حذفه (<code>remove</code>) أو إما إضافته إن لم يكن موجودًا أو حذفه إن وُجد (<code>toggle</code>).كما هو مبين في المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7651_11" style="">
<span class="tag">&lt;body</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"main page"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;script&gt;</span><span class="pln">
    </span><span class="com">// إضافة صنف</span><span class="pln">
    document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">classList</span><span class="pun">.</span><span class="pln">add</span><span class="pun">(</span><span class="str">'article'</span><span class="pun">);</span><span class="pln">
    alert</span><span class="pun">(</span><span class="pln">document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">className</span><span class="pun">);</span><span class="pln"> </span><span class="com">// main page article</span><span class="pln">
  </span><span class="tag">&lt;/script&gt;</span><span class="pln">
</span><span class="tag">&lt;/body&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-08-Styles and classes-ex2" src="https://codepen.io/Hsoub/embed/preview/XWNrywK?height=265&amp;theme-id=light&amp;default-tab=html,result">See the Pen JS-p2-08-Styles and classes-ex2 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	وبذلك يمكننا إجراء عمليات على مجمل سلسلة الأصناف دفعة واحدة باستعمال <code>className</code> أو على الأصناف، كلٌّ على حدى، باستعمال <code>classList</code>. اختيارنا لهذا أو ذاك مرتبط بما نحتاج القيام به.
</p>

<p>
	الدوالّ الخاصة بـالخاصية <code>classList</code> هي: *<code>elem.classList.add/remove("class")‎</code>: إضافة الصنف المذكور كوسيط للدلّة/حذف الصنف المذكور كوسيط للدلّة. *<code>elem.classList.toggle("classe")‎</code>: إضافة الصنف المذكور كوسيط للدلّة إن لم يكن موجودًا أو حذفه إن وُجد. *<code>elem.classList.contains("class")‎</code>: البحث عن الصنف المذكور كوسيط للدلّة، والنتيجة تكون صحيح أو خطأ (true/false).
</p>

<p>
	وتقبل الخاصية <code>classList</code> الإدماج داخل حلقة التكرار <code>for....of</code> لإظهار قائمة الأصناف كما في المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7651_13" style="">
<span class="tag">&lt;body</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"main page"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;script&gt;</span><span class="pln">
    </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let name of document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">classList</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      alert</span><span class="pun">(</span><span class="pln">name</span><span class="pun">);</span><span class="pln"> </span><span class="com">// main, and then page</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="tag">&lt;/script&gt;</span><span class="pln">
</span><span class="tag">&lt;/body&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-08-Styles and classes-ex3" src="https://codepen.io/Hsoub/embed/preview/oNYvQRG?height=265&amp;theme-id=light&amp;default-tab=html,result">See the Pen JS-p2-08-Styles and classes-ex3 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<h2>
	تنسيق العنصر باستعمال الخاصية <code>style</code>
</h2>

<p>
	تُعدّ الخاصية <code>elem.style</code> كائنًا يحمل محتوى السمة <code>style</code>. ويؤدي إسناد القيمة <code>"100px"</code> للخاصية <code>elem.style.width</code> على الشكل التالي: <code>elem.style.width="100px"</code> إلى النتيجة نفسها لو كانت السمة <code>style</code> تحمل السلسلة النصية <code>"width:100px"</code>.
</p>

<p>
	إذا كان اسم السمة يتكون من عدة كلمات، يُشكَّل اسم الخاصية بجعل الحرف الأول من كل كلمة حرفا كبيرًا ماعدا الكلمة الأولى كما في المثال التالي:
</p>

<pre class="ipsCode" id="ips_uid_7651_15">
background-color  =&gt; elem.style.backgroundColor
z-index           =&gt; elem.style.zIndex
border-left-width =&gt; elem.style.borderLeftWidth
</pre>

<hr>
<p>
	<strong>ملاحظة: الخاصيات التي تبدأ ببادئة</strong>
</p>

<p>
	تتبع الخاصيات التي تبدأ ببادئة تُحدّد المتصفح نفس القاعدة، كالخاصيتين <code>-moz-border-radius</code> و<code>-webkit-border-radius</code>، حيث تُترجَم الشرطة إلى حرفٍ كبيرٍ كالآتي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7651_17" style="">
<span class="pln">button</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="typ">MozBorderRadius</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">'5px'</span><span class="pun">;</span><span class="pln">
button</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="typ">WebkitBorderRadius</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">'5px'</span><span class="pun">;</span></pre>

<hr>
<h2>
	تغيير قيمة خاصية التنسيق <code>style</code>
</h2>

<p>
	يحدث أن تَرغب في إسناد قيمةٍ للخاصية <code>style</code> ثم حذفها لاحقا. يمكننا على سبيل المثال إسناد القيمة <code>"none"</code> للخاصية <code>elem.style.display</code> كالأتي <code>elem.style.display = "none"</code> ثم حذفها وكأننا لم نحدّد لها قيمةً من قبل. هنا، ينبغي إسناد سلسلة نصية فارغة للخاصية <code>elem.style.display</code> كالآتي <code>elem.style.display = ""‎</code> بدلا من حذفها (<code>delete</code>).
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7651_19" style="">
<span class="com">//عند تنفيذ هذا السكربت يختفي العنصر &lt;body&gt; ثمّ يُعاود الظهور</span><span class="pln">
document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">display </span><span class="pun">=</span><span class="pln"> </span><span class="str">"none"</span><span class="pun">;</span><span class="pln"> </span><span class="com">// يختفي </span><span class="pln">

setTimeout</span><span class="pun">(()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">display </span><span class="pun">=</span><span class="pln"> </span><span class="str">""</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1000</span><span class="pun">);</span><span class="pln"> </span><span class="com">// يُعاود الظهور</span></pre>

<p>
	إذا أسندنا سلسلة نصية فارغة للخاصية <code>style.display</code>، يُطبِّق المتصفح أصناف CSS والأنماط التنسيقية المتضمَّنة بداخلها بطريقة عاديةٍ جدًا وكأن الخاصية <code>style.display</code> غير موجودة تماما.
</p>

<p>
	<strong>ملاحظة: التعديل على خاصيات الخاصية <code>style</code> جملةً واحدةً باستعمال الخاصية <code>style.cssStyle</code></strong>
</p>

<p>
	تُستعمل عادة الخاصية <code>*.style</code> للتعديل على قيم خاصيات التنسيق، كلٌ على حدى، ولا يمكننا التعديل عليها دفعة واحدة كالآتي: <code>div.style="color:red; width:100px"</code>‎، لأن <code>div.style</code> هو كائنٌ لا يمكن التعديل عليه (ِread-only) بهذه الطريقة.
</p>

<p>
	يمكن تغيير التنسيق كاملا دفعة واحدة بإسناد سلسلة نصية (تحمل وصف التنسيق) للخاصية <code>style.cssStyle</code> كما في المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7651_21" style="">
<span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"div"</span><span class="tag">&gt;</span><span class="pln">Button</span><span class="tag">&lt;/div&gt;</span><span class="pln">
</span><span class="tag">&lt;script&gt;</span><span class="pln">
  </span><span class="com">// يمكننا استعمال رايات تنسيقية خاصة مثل الراية “important” </span><span class="pln">
    div</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">cssText</span><span class="pun">=`</span><span class="pln">color</span><span class="pun">:</span><span class="pln"> red </span><span class="pun">!</span><span class="pln">important</span><span class="pun">;</span><span class="pln">
    background</span><span class="pun">-</span><span class="pln">color</span><span class="pun">:</span><span class="pln"> yellow</span><span class="pun">;</span><span class="pln">
    width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">100px</span><span class="pun">;</span><span class="pln">
    text</span><span class="pun">-</span><span class="pln">align</span><span class="pun">:</span><span class="pln"> center</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">`;</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln">div</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">cssText</span><span class="pun">);</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-08-Styles and classes-ex4" src="https://codepen.io/Hsoub/embed/preview/rNWBQEe?height=265&amp;theme-id=light&amp;default-tab=result">See the Pen JS-p2-08-Styles and classes-ex4 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	غير أنه من النادر استعمال هذه الخاصية كونها تحذف الأنماط التنسيقية السابقة وتستبدلها بالقيم الجديدة، أي أنها قد تحذف أشياء مازلنا بحاجتها. فيما يمكن أن تُستخدم لتنسيق العناصر الجديدة، فلن يؤدي إسناد القيم بهذه الطريقة إلى أيّ عملية حذف (بما أن العناصر الجديدة لا تملك تنسيقات بعد). ويمكننا عمل ذلك أيضا باستعمال الدالّة <code>div.setAttribute('style', 'color: red...')‎</code>.
</p>

<h2>
	الوحدات
</h2>

<p>
	لا تنس إضافة الوحدات للقيم في شيفرة CSS، فلا يصِحُّ إسناد القيمة "10" للخاصية <code>elem.style.top</code> بل القيمة <code>10px</code> هي الأصح، وإلا فلن يعمل السكربت بالشكل المطلوب.
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7651_23" style="">
<span class="tag">&lt;body&gt;</span><span class="pln">
  </span><span class="tag">&lt;script&gt;</span><span class="pln">
    </span><span class="com">// لا يعمل</span><span class="pln">
    document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">margin </span><span class="pun">=</span><span class="pln"> </span><span class="lit">20</span><span class="pun">;</span><span class="pln">
    alert</span><span class="pun">(</span><span class="pln">document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">margin</span><span class="pun">);</span><span class="pln"> </span><span class="com">// '' (سلسلة نصية فارغة، إهمال عملية الإسناد)</span><span class="pln">
    </span><span class="com">// يعمل بعد إضافة الوحدة </span><span class="pln">
    document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">margin </span><span class="pun">=</span><span class="pln"> </span><span class="str">'20px'</span><span class="pun">;</span><span class="pln">
    alert</span><span class="pun">(</span><span class="pln">document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">margin</span><span class="pun">);</span><span class="pln"> </span><span class="com">// 20px</span><span class="pln">
    alert</span><span class="pun">(</span><span class="pln">document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">marginTop</span><span class="pun">);</span><span class="pln"> </span><span class="com">// 20px</span><span class="pln">
    alert</span><span class="pun">(</span><span class="pln">document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">marginLeft</span><span class="pun">);</span><span class="pln"> </span><span class="com">// 20px</span><span class="pln">
  </span><span class="tag">&lt;/script&gt;</span><span class="pln">
</span><span class="tag">&lt;/body&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-08-Styles and classes-ex5" src="https://codepen.io/Hsoub/embed/preview/KKNPrOP?height=265&amp;theme-id=light&amp;default-tab=html,result">See the Pen JS-p2-08-Styles and classes-ex5 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	لاحظ في السطرين الأخيرين أن المتصفح يفكّك الخاصية <code>style.margin</code> إلى خاصيتين وهما: <code>style.marginLeft</code> و<code>style.marginTop</code>.
</p>

<h2>
	الأنماط المحسوبة باستعمال الدالة getComputedStyle
</h2>

<p>
	يُعدّ التعديل على الأنماط عمليةً سهلةً ولكن كيف تُقرأ الأنماط؟ نريد مثلا معرفة مقاس، هوامش ولون عنصرٍ ما، كيف نتحصل عليها؟
</p>

<p>
	تعمل الخاصية <code>style</code> على تعديل قيمة السمة <code>style</code> فقط دون الوصول إلى الأنماط الموصوفة في الأوراق التنسيقية المتتالية CSS. وبالتالي لا يمكننا قراءة أيّ قيمٍ من أصناف CSS باستعمال الخاصية <code>elem.style</code>. فعلى سبيل المثال لا يمكن أن تصل الخاصية <code>style</code> في هذا المثال إلى الهامش.
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7651_25" style="">
<span class="tag">&lt;head&gt;</span><span class="pln">
  </span><span class="tag">&lt;style&gt;</span><span class="pln"> body </span><span class="pun">{</span><span class="pln"> color</span><span class="pun">:</span><span class="pln"> red</span><span class="pun">;</span><span class="pln"> margin</span><span class="pun">:</span><span class="pln"> </span><span class="lit">5px</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> </span><span class="tag">&lt;/style&gt;</span><span class="pln">
</span><span class="tag">&lt;/head&gt;</span><span class="pln">
</span><span class="tag">&lt;body&gt;</span><span class="pln">
  The red text
  </span><span class="tag">&lt;script&gt;</span><span class="pln">
    alert</span><span class="pun">(</span><span class="pln">document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">color</span><span class="pun">);</span><span class="pln"> </span><span class="com">// فارغة </span><span class="pln">
    alert</span><span class="pun">(</span><span class="pln">document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">marginTop</span><span class="pun">);</span><span class="pln"> </span><span class="com">// فارغة </span><span class="pln">
  </span><span class="tag">&lt;/script&gt;</span><span class="pln">
</span><span class="tag">&lt;/body&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-08-Styles and classes-ex6" src="https://codepen.io/Hsoub/embed/preview/abBoQep?height=265&amp;theme-id=light&amp;default-tab=html,result">See the Pen JS-p2-08-Styles and classes-ex6 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	ماذا لو أردنا على سبيل المثال إضافة 20px للهامش؟ سيكون علينا أولا الوصول إلى القيمة الحالية له حتى يتسنى لنا تعديلها. وهنا لدينا طريقة أخرى للحصول على ذلك وتكون باستعمال الدالة <code>getComputedStyle</code> وبنيتها كالآتي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7651_27" style="">
<span class="pln">getComputedStyle</span><span class="pun">(</span><span class="pln">element</span><span class="pun">,</span><span class="pln"> </span><span class="pun">[</span><span class="pln">pseudo</span><span class="pun">])</span></pre>

<p>
	حيث يمثّل العنصر <code>element</code> العنصر الذي سنحسب قيمه ويمثل <code>pseudo</code> العنصر الزائف، مثلا <code>before::</code>. إذا كانت قيمة <code>pseudo</code> عبارة عن سلسلة نصية فارغة أو غير موجودة أصلا فهذا يعني أننا نقصد العنصر نفسه. وتكون مخرجات الدالّة (output) عبارة عن كائن يحوي أنماط تنسيقية مثله مثل <code>elem.style</code> ولكن يأخذ في الحسبان هذه المرة كلّ الأصناف الموجودة في ملف CSS. وفيما يلي مثال على ذلك:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7651_29" style="">
<span class="tag">&lt;head&gt;</span><span class="pln">
  </span><span class="tag">&lt;style&gt;</span><span class="pln"> body </span><span class="pun">{</span><span class="pln"> color</span><span class="pun">:</span><span class="pln"> red</span><span class="pun">;</span><span class="pln"> margin</span><span class="pun">:</span><span class="pln"> </span><span class="lit">5px</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> </span><span class="tag">&lt;/style&gt;</span><span class="pln">
</span><span class="tag">&lt;/head&gt;</span><span class="pln">
</span><span class="tag">&lt;body&gt;</span><span class="pln">
  </span><span class="tag">&lt;script&gt;</span><span class="pln">
    let computedStyle </span><span class="pun">=</span><span class="pln"> getComputedStyle</span><span class="pun">(</span><span class="pln">document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">);</span><span class="pln">
    </span><span class="com">// يمكننا الآن قراءة اللون والهامش </span><span class="pln">
    alert</span><span class="pun">(</span><span class="pln"> computedStyle</span><span class="pun">.</span><span class="pln">marginTop </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 5px</span><span class="pln">
    alert</span><span class="pun">(</span><span class="pln"> computedStyle</span><span class="pun">.</span><span class="pln">color </span><span class="pun">);</span><span class="pln"> </span><span class="com">// rgb(255, 0, 0)</span><span class="pln">
  </span><span class="tag">&lt;/script&gt;</span><span class="pln">
</span><span class="tag">&lt;/body&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-08-Styles and classes-ex7" src="https://codepen.io/Hsoub/embed/preview/jOVNQgg?height=265&amp;theme-id=light&amp;default-tab=html,result">See the Pen JS-p2-08-Styles and classes-ex7 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<hr>
<p>
	<strong>ملاحظة: القيم المحسوبة والقيم النهائية (المُحدَّدة)</strong>
</p>

<p>
	هناك مفهومان في لغة CSS هما:
</p>

<ol>
<li>
		قيمة تنسيقية محسوبة وهي القيمة المتحصّل عليها بعد تطبيق مجمل القواعد التنسيقية وقواعد الوراثة المُتضمَّنة في ملف CSS. قد تكون على شكل <code>height:1em</code> أو <code>font-size:125%</code> .
	</li>
	<li>
		قيمة تنسيقية نهائية (مُحدَّدة) وهي القيمة التي يقع عليها الاختيار في آخر المطاف وتُطبَّق على العنصر. القيمتان <code>1em</code> و<code>125%</code> هما قيمتان نسبيتان. يأخذ المتصفح كافة القيم المحسوبة ويجعل كافة الوحدات مطلقة كما في المثال التالي: <code>height:20px</code> ،<code>font-size:16px</code>. ويمكن للقيم النهائية الخاصة بالخاصيات الهندسية أن تكون عشرية مثل: <code>width:50.5px</code>.
	</li>
</ol>
<p>
	لقد اُستحدثت الدالّة <code>getComputedStyle</code> أساسا للحصول على قيم محسوبة ولكن تبيّن فيما بعد أن القيم النهائية (المُحدَّدة) أحسن، فتغيرت المعايير، وأصبحت الدالّة <code>getComputedStyle</code> تُخرِج القيم النهائية للخاصية والتي تكون غالبا بالبكسل px بالنسبة للخاصيات الهندسية.
</p>

<hr>
<p>
	<strong>ملاحظة: تتطلب الدالة <code>getComputedStyle</code> ذكر الاسم الكامل للخاصية</strong>
</p>

<p>
	علينا البحث على الدوام عن الخاصية التي نحتاج إليها بدقة مثل: padingLeft، أو marginTop أو borderTopWidth وإلا فلن نتمكن من ضمان صحة النتيجة المتحصّل عليها. فمع وُجود، على سبيل المثال، الخاصيتين padingLeft/padingTop، على ماذا سوف نحصل عند تنفيذ الدالّة <code>getComputedStyle(elem, pading)‎</code>؟
</p>

<p>
	لن نحصل على شيئ؟ أو ربما سنحصل على قيمة "مستوحاة" من قيم معرّفة مسبقا للحاشية (pading)؟ في الحقيقة لا يوجد أيّ معايير تتحدث عن هذا الموضوع.
</p>

<p>
	وهناك بعض التناقضات الأخرى، حيث تُظهِر بعض المتصفحات (Chrome مثلا) في مثال الموالي القيمة <code>10px</code>، ولا تُظهِرها متصفحات أخرى (كالمتصفح Firefox).
</p>

<p>
	مثال:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7651_31" style="">
<span class="tag">&lt;style&gt;</span><span class="pln">
  body </span><span class="pun">{</span><span class="pln">
    margin</span><span class="pun">:</span><span class="pln"> </span><span class="lit">10px</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="tag">&lt;/style&gt;</span><span class="pln">
</span><span class="tag">&lt;script&gt;</span><span class="pln">
  let style </span><span class="pun">=</span><span class="pln"> getComputedStyle</span><span class="pun">(</span><span class="pln">document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">);</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln">style</span><span class="pun">.</span><span class="pln">margin</span><span class="pun">);</span><span class="pln"> </span><span class="com">// نحصل على سلسلة فارغة عند استعمال المتصفح Firefox </span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-08-Styles and classes-ex8" src="https://codepen.io/Hsoub/embed/preview/qBqWLWX?height=265&amp;theme-id=light&amp;default-tab=html,result">See the Pen JS-p2-08-Styles and classes-ex8 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<hr>
<p>
	<strong>ملاحظة: الأنماط التي تُطبَّق على الروابط <code>‎:visited</code> تكون مخفية</strong>
</p>

<p>
	يمكن تلوين الروابط التي سبق وأن زيرت باستخدام الصنف الزائف <code>‎:visited</code> في ملف CSS. لكن الدالّة <code>getComputedStyle</code> لا يمكنها الوصول إلى هذا اللون، لأن ذلك يمكِّن أيّ صفحة كانت من إنشاء الرابط على الصفحة والإطلاع على الأنماط وبالتالي معرفة ما إذا كان المستخدم قد زار الرابط من قبل.
</p>

<p>
	لا يمكن للغة جافاسكربت الإطلاع على الأنماط المعرّفة باستخدام الصنف الزائف <code>‎:visited</code>، كما تمنع لغة CSS تطبيق تنسيقاتِ تغيير الشكل والأبعاد (geometry-changing styles) ضمن الصنف الزائف <code>‎:visited</code> وذلك لغلق الطريق أمام أيّ صفحةٍ مشبوهةٍ تسعى لمعرفة ما إذا زار المستخدم الرابط أم لا، وبالتالي التعدي على خصوصيته.
</p>

<hr>
<h2>
	الخلاصة
</h2>

<p>
	هناك خاصيتان تُستخدمان للعمل على الأصناف وهما:
</p>

<ul>
<li>
		<code>className</code>: وهي سلسلة نصية تُستخدم للعمل على كافة الأصناف دفعةً واحدةً.
	</li>
	<li>
		<code>classList</code>: هي عبارة عن كائن له دوالّه الخاصة (add/delete/toggle/contains) وتستخدم للعمل على الأصناف، كلُ على حدى.
	</li>
</ul>
<p>
	ولتغيير التنسيق لدينا:
</p>

<ul>
<li>
		الخاصية <code>style</code>؛ وهي عبارة عن كائن تُشكَّل خواصه بجعل الحرف الأول من كل كلمة حرفا كبيرًا ما عدا الكلمة الأولى. تُعدّ قراءته والتعديل عليه تماما كالتعديل على خاصيات السمة <code>style</code>، كلٌ على حدى. وللاطلاع على كيفية إضافة الراية important وغيرها، يمكنك زيارة موقع <a href="https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleDeclaration" rel="external nofollow">MDN</a> حيث تجد قائمة من الدوالّ التي تُستخدم لذلك.
	</li>
	<li>
		الخاصية <code>style.cssText</code>: هي الخاصية التي تقابِل السمة <code>"style"</code> في مجملها، أي السلسلة النصية التي تحمل كافة الأنماط التنسيقية دفعةً واحدةً.
	</li>
</ul>
<p>
	ولقراءة الأنماط التنسيقية النهائية (التي تأخذ في الحسبان كافة الأصناف بعد تطبيق تنسيقات CSS وحساب القيم النهائية) وُجدَت الدالة <code>getComputedStyle(elem, [pseudo])‎</code> والتي تخرِج/تعيد كائنا يحمل التنسيقات وهو قابلٌ للقراءة فقط.
</p>

<h2>
	تمرين
</h2>

<h3>
	إنشاء إشعار
</h3>

<p>
	<em>درجة الأهمية: 5</em>
</p>

<p>
	اكتب شيفرة الدالّة <code>showNotification(options)‎</code> التي تُنشِئ إشعارًا كالآتي:
</p>

<div class="notification">
	بالمحتوى الذي يُمرَّر لها كوسيط، حيث يختفي الإشعار بعد ثانية ونصف من إظهاره. وتُوفّر الخيارات التالية:
	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7651_33" style="">
<span class="com">// أظهِر عنصرًا يحمل النص "Hello" بالقرب من الركن العلوي الأيمن للنافذة  </span><span class="pln">
showNotification</span><span class="pun">({</span><span class="pln">
  top</span><span class="pun">:</span><span class="pln"> </span><span class="lit">10</span><span class="pun">,</span><span class="pln"> </span><span class="com">// عشرة بكسل بدءًا من أعلى النافذة والذي فاصلته 0</span><span class="pln">
  right</span><span class="pun">:</span><span class="pln"> </span><span class="lit">10</span><span class="pun">,</span><span class="pln"> </span><span class="com">// عشرة بكسل بدءًا من الحافة اليمنى للنافذة والتي ترتيبتها 0</span><span class="pln">
  html</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Hello!"</span><span class="pun">,</span><span class="pln"> </span><span class="com">// شيفرة HTML الخاصة بالإشعار</span><span class="pln">
  className</span><span class="pun">:</span><span class="pln"> </span><span class="str">"welcome"</span><span class="pln"> </span><span class="com">// صنف إضافي للحاوية ‘div’ (اختياري)</span><span class="pln">
</span><span class="pun">});</span></pre>

	<p>
		استعمل تنسيقات CSS لتحديد موضع إظهار العنصر حسب الإحداثيات المعطاة بافتراض أن الصفحة تحتوي مسبقا على الأنماط التنسيقية الضرورية.
	</p>

	<h4>
		<strong>الحل</strong>
	</h4>

	<p>
		<a href="https://plnkr.co/edit/iSJDfGZFJcTpZ4vq?p=preview&amp;preview" rel="external nofollow">يمكنك الإطلاع على الحل من هنا</a>
	</p>

	<p>
		ترجمة -وبتصرف- للفصل <a href="https://javascript.info/styles-and-classes" rel="external nofollow">Styles and classes</a> من كتاب <a href="https://javascript.info/ui" rel="external nofollow">Browser: Document, Events, Interfaces</a>
	</p>
</div>
]]></description><guid isPermaLink="false">1118</guid><pubDate>Mon, 01 Feb 2021 13:08:01 +0000</pubDate></item><item><title>&#x627;&#x644;&#x62A;&#x639;&#x62F;&#x64A;&#x644; &#x639;&#x644;&#x649; &#x635;&#x641;&#x62D;&#x629; HTML &#x639;&#x628;&#x631; &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A;</title><link>https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%AA%D8%B9%D8%AF%D9%8A%D9%84-%D8%B9%D9%84%D9%89-%D8%B5%D9%81%D8%AD%D8%A9-html-%D8%B9%D8%A8%D8%B1-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r1117/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_01/6013f360ea022_---HTML--.png.90e82e41ce550ff12c0344c8728e80bf.png" /></p>

<p>
	يُعدّ التعديل على نموذج تمثيل المستند ككائن (DOM) مفتاح الحصول على صفحات "حيّة" (ديناميكية). سوف تتعرف فيما يلي على كيفية إنشاء عناصر جديدة على الصفحات في لمح البصر (بطريقة آنية دون الحاجة إلى إعادة تحميل الصفحات).
</p>

<h2>
	مثال: إظهار رسالة
</h2>

<p>
	فلنعرض ذلك على شكل مثالٍ تطبيقيٍ، حيث نُضيف رسالةً للصفحة تكون أكثر تنسيقًا من رسالة <code>alert</code> كالآتي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5648_7" style="">
<span class="tag">&lt;style&gt;</span><span class="pln">
</span><span class="pun">.</span><span class="pln">alert </span><span class="pun">{</span><span class="pln">
  padding</span><span class="pun">:</span><span class="pln"> </span><span class="lit">15px</span><span class="pun">;</span><span class="pln">
  border</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1px</span><span class="pln"> solid </span><span class="com">#d6e9c6;</span><span class="pln">
  border</span><span class="pun">-</span><span class="pln">radius</span><span class="pun">:</span><span class="pln"> </span><span class="lit">4px</span><span class="pun">;</span><span class="pln">
  color</span><span class="pun">:</span><span class="pln"> </span><span class="com">#3c763d;</span><span class="pln">
  background</span><span class="pun">-</span><span class="pln">color</span><span class="pun">:</span><span class="pln"> </span><span class="com">#dff0d8;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="tag">&lt;/style&gt;</span><span class="pln">
</span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"alert"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;strong&gt;</span><span class="pln">Hi there!</span><span class="tag">&lt;/strong&gt;</span><span class="pln"> You've read an important message.
</span><span class="tag">&lt;/div&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-07-Modifying the document-ex1" src="https://codepen.io/Hsoub/embed/RwobqgZ?height=265&amp;theme-id=light&amp;default-tab=html,result">See the Pen JS-p2-07-Modifying the document-ex1 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	استعملنا في هذا المثال لغة HTML. فلنُنشئ نفس الحاوية <code>div</code> باستخدام جافاسكربت (على افتراض أن شيفرة HTML/CSS تتضمّن الأنماط التنسيقية).
</p>

<h2>
	إنشاء عنصر ما
</h2>

<p>
	توجد طريقتان لإنشاء عناصر (DOM):
</p>

<ul>
<li>
		<strong>الدالّة <code>(document.createElement(tag</code></strong>: تُستخدم لإنشاء عقدة عناصرية جديدة باستعمال الوسم الذي يُمرَّر لها كالآتي:
	</li>
</ul>
<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5648_9" style="">
<span class="pln">let div </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">createElement</span><span class="pun">(</span><span class="str">'div'</span><span class="pun">);</span></pre>

<ul>
<li>
		<strong>الدالّة <code>(document.createTextNode(text</code></strong>: تُستخدم لإنشاء عقدة نصية جديدة باستعمال النص الذي يُمرَّر لها كالآتي:
	</li>
</ul>
<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5648_11" style="">
<span class="pln">let textNode </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">createTextNode</span><span class="pun">(</span><span class="str">'Here I am'</span><span class="pun">);</span></pre>

<p>
	غالبا ما نحتاج إلى إنشاء عقدٍ عناصريةٍ، مثل الحاوية <code>div</code>، من أجل إظهار الرسالة.
</p>

<h3>
	إنشاء الرسالة
</h3>

<p>
	يتطلّب إنشاء حاوية الرسالة <code>div</code> ثلاث مراحل:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5648_13" style="">
<span class="com">// 1. إنشاء العنصر &lt;div&gt;</span><span class="pln">
let div </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">createElement</span><span class="pun">(</span><span class="str">'div'</span><span class="pun">);</span><span class="pln">

</span><span class="com">// 2. إسناد القيمة "alert"  لصنف الحاوية </span><span class="pln">
div</span><span class="pun">.</span><span class="pln">className </span><span class="pun">=</span><span class="pln"> </span><span class="str">"alert"</span><span class="pun">;</span><span class="pln">

</span><span class="com">// 3. وضع المحتوى داخل الحاوية </span><span class="pln">
div</span><span class="pun">.</span><span class="pln">innerHTML </span><span class="pun">=</span><span class="pln"> </span><span class="str">"&lt;strong&gt;Hi there!&lt;/strong&gt; You've read an important message."</span><span class="pun">;</span></pre>

<p>
	صحيحٌ أنّنا أنشأنا العنصر ولكنه لحد الآن غير ظاهرٍ في الصفحة لأنّنا أنشأناه داخل المتغيّر <code>div</code> ولم نُضفه بعد للصفحة.
</p>

<h2>
	دوالّ إضافة العناصر للصفحة
</h2>

<p>
	من أجل إظهار الحاوية <code>div</code>، نحتاج إلى إضافتها في موضع ما من الصفحة، داخل العنصر <code>&lt;body&gt;</code> مثلا والمشار إليه بالكائن <code>document.body</code>. توجد دالّة خاصة تسمّى append تساعد على ذلك كما هو موضّح في المثال الآتي (انظر السطر الموسوم بـ (*)):
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5648_15" style="">
<span class="tag">&lt;style&gt;</span><span class="pln">
</span><span class="pun">.</span><span class="pln">alert </span><span class="pun">{</span><span class="pln">
  padding</span><span class="pun">:</span><span class="pln"> </span><span class="lit">15px</span><span class="pun">;</span><span class="pln">
  border</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1px</span><span class="pln"> solid </span><span class="com">#d6e9c6;</span><span class="pln">
  border</span><span class="pun">-</span><span class="pln">radius</span><span class="pun">:</span><span class="pln"> </span><span class="lit">4px</span><span class="pun">;</span><span class="pln">
  color</span><span class="pun">:</span><span class="pln"> </span><span class="com">#3c763d;</span><span class="pln">
  background</span><span class="pun">-</span><span class="pln">color</span><span class="pun">:</span><span class="pln"> </span><span class="com">#dff0d8;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="tag">&lt;/style&gt;</span><span class="pln">

</span><span class="tag">&lt;script&gt;</span><span class="pln">
  let div </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">createElement</span><span class="pun">(</span><span class="str">'div'</span><span class="pun">);</span><span class="pln">
  div</span><span class="pun">.</span><span class="pln">className </span><span class="pun">=</span><span class="pln"> </span><span class="str">"alert"</span><span class="pun">;</span><span class="pln">
  div</span><span class="pun">.</span><span class="pln">innerHTML </span><span class="pun">=</span><span class="pln"> </span><span class="str">"&lt;strong&gt;Hi there!&lt;/strong&gt; You've read an important message."</span><span class="pun">;</span><span class="pln">

  document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">append</span><span class="pun">(</span><span class="pln">div</span><span class="pun">);</span><span class="com">//(*)</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-07-Modifying the document-ex2" src="https://codepen.io/Hsoub/embed/eYBOQRq?height=265&amp;theme-id=light&amp;default-tab=html,result">See the Pen JS-p2-07-Modifying the document-ex2 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	نادينا، في هذا المثال، الدالّة <code>append</code> وطبقناها على الكائن <code>document.body</code>. كان يمكن أن نُطبقها على أيّ عنصرٍ كان من أجل إضافة عنصرٍ آخر له، حيث يمكننا على سبيل المثال إضافة عنصر ما للعنصر <code>&lt;div&gt;</code> باستعمال الدالّة <code>div.append(anotherElement)‎</code>. وهذه قائمة دوالّ غيرها تُستعمل لإضافة عنصرٍ ما لعنصرٍ آخرٍ في موضعٍ معيّنٍ من الصفحة:
</p>

<ul>
<li>
		<code>node.append(...nodes or strings)‎</code>: إضافة عقد أو سلاسل نصية في نهاية العقدة <code>node</code>.
	</li>
	<li>
		<code>node.prepend(...nodes or strings)‎</code>: إضافة عقد أو سلاسل نصية في بداية العقدة <code>node</code>.
	</li>
	<li>
		<code>node.before(...nodes or strings)‎</code>: إضافة عقد أو سلاسل نصية قبل العقدة <code>node</code>.
	</li>
	<li>
		<code>node.after(...nodes or strings)‎</code>: إضافة عقد أو سلاسل نصية بعد العقدة <code>node</code>.
	</li>
	<li>
		<code>node.replaceWith(...nodes or strings)‎</code>: وضع عقد أو سلاسل نصية مكان العقدة <code>node</code>.
	</li>
</ul>
<p>
	وتكون وسائط هذه الدوالّ عبارة عن قائمة عشوائية من عقد DOM أو سلاسل نصية (التي تصبح آليا عقدًا نصية). دعنا نرى ذلك عبر المثال الحيّ التالي، حيث تُستخدم فيه هذه الدوالّ لإضافة عناصر <code>li</code> لقائمة ما ونصين، أحدهما قبلها والآخر بعدها.
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5648_17" style="">
<span class="tag">&lt;ol</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"ol"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;li&gt;</span><span class="pln">0</span><span class="tag">&lt;/li&gt;</span><span class="pln">
  </span><span class="tag">&lt;li&gt;</span><span class="pln">1</span><span class="tag">&lt;/li&gt;</span><span class="pln">
  </span><span class="tag">&lt;li&gt;</span><span class="pln">2</span><span class="tag">&lt;/li&gt;</span><span class="pln">
</span><span class="tag">&lt;/ol&gt;</span><span class="pln">

</span><span class="tag">&lt;script&gt;</span><span class="pln">
  ol</span><span class="pun">.</span><span class="pln">before</span><span class="pun">(</span><span class="str">'before'</span><span class="pun">);</span><span class="pln"> </span><span class="com">// إضافة السلسلة "before" قبل العنصر &lt;ol&gt;</span><span class="pln">
  ol</span><span class="pun">.</span><span class="pln">after</span><span class="pun">(</span><span class="str">'after'</span><span class="pun">);</span><span class="pln"> </span><span class="com">// إضافة السلسلة "after" بعد العنصر &lt;ol&gt;</span><span class="pln">

  let liFirst </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">createElement</span><span class="pun">(</span><span class="str">'li'</span><span class="pun">);</span><span class="pln">
  liFirst</span><span class="pun">.</span><span class="pln">innerHTML </span><span class="pun">=</span><span class="pln"> </span><span class="str">'prepend'</span><span class="pun">;</span><span class="pln">
  ol</span><span class="pun">.</span><span class="pln">prepend</span><span class="pun">(</span><span class="pln">liFirst</span><span class="pun">);</span><span class="pln"> </span><span class="com">// إضافة  العنصر liFirst في بداية القائمة  &lt;ol&gt;</span><span class="pln">

  let liLast </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">createElement</span><span class="pun">(</span><span class="str">'li'</span><span class="pun">);</span><span class="pln">
  liLast</span><span class="pun">.</span><span class="pln">innerHTML </span><span class="pun">=</span><span class="pln"> </span><span class="str">'append'</span><span class="pun">;</span><span class="pln">
  ol</span><span class="pun">.</span><span class="pln">append</span><span class="pun">(</span><span class="pln">liLast</span><span class="pun">);</span><span class="pln"> </span><span class="com">// إضافة  العنصر liLast في نهاية القائمة  &lt;ol&gt;</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-07-Modifying the document-ex3" src="https://codepen.io/Hsoub/embed/vYyBQJZ?height=265&amp;theme-id=light&amp;default-tab=html,result">See the Pen JS-p2-07-Modifying the document-ex3 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="56604" href="https://academy.hsoub.com/uploads/monthly_2021_01/001insertionMethodsExample.png.e87ef422dd8eb8513dd098767010d415.png" rel=""><img alt="001insertionMethodsExample.png" class="ipsImage ipsImage_thumbnailed" data-fileid="56604" data-unique="6hske4swk" src="https://academy.hsoub.com/uploads/monthly_2021_01/001insertionMethodsExample.png.e87ef422dd8eb8513dd098767010d415.png"></a>
</p>

<p>
	وفيما يلي صورةٌ توضيحيةٌ لما تقوم به هذه الدوالّ:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="56605" href="https://academy.hsoub.com/uploads/monthly_2021_01/002insertionMethods.png.beec6751695a2b76805abc4ed9661c8b.png" rel=""><img alt="002insertionMethods.png" class="ipsImage ipsImage_thumbnailed" data-fileid="56605" data-unique="o0om5x39p" src="https://academy.hsoub.com/uploads/monthly_2021_01/002insertionMethods.png.beec6751695a2b76805abc4ed9661c8b.png"></a>
</p>

<p>
	وبالتالي تصبح القائمة في شكلها النهائي كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5648_19" style="">
<span class="pln">before
</span><span class="tag">&lt;ol</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"ol"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;li&gt;</span><span class="pln">prepend</span><span class="tag">&lt;/li&gt;</span><span class="pln">
  </span><span class="tag">&lt;li&gt;</span><span class="pln">0</span><span class="tag">&lt;/li&gt;</span><span class="pln">
  </span><span class="tag">&lt;li&gt;</span><span class="pln">1</span><span class="tag">&lt;/li&gt;</span><span class="pln">
  </span><span class="tag">&lt;li&gt;</span><span class="pln">2</span><span class="tag">&lt;/li&gt;</span><span class="pln">
  </span><span class="tag">&lt;li&gt;</span><span class="pln">append</span><span class="tag">&lt;/li&gt;</span><span class="pln">
</span><span class="tag">&lt;/ol&gt;</span><span class="pln">
after</span></pre>

<p>
	وكما سبق أن ذكرنا، يُمكننا إضافة العديد من العقد والسلاسل النصية بمناداة الدالّة مرّةً واحدةً فقط. في المثال التالي، أُضيفت كلٌّ من السلسلة النصية والعنصر دفعةً واحدةً:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5648_21" style="">
<span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"div"</span><span class="tag">&gt;&lt;/div&gt;</span><span class="pln">
</span><span class="tag">&lt;script&gt;</span><span class="pln">
  div</span><span class="pun">.</span><span class="pln">before</span><span class="pun">(</span><span class="str">'&lt;p&gt;Hello&lt;/p&gt;'</span><span class="pun">,</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">createElement</span><span class="pun">(</span><span class="str">'hr'</span><span class="pun">));</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-07-Modifying the document-ex4" src="https://codepen.io/Hsoub/embed/oNYvQGB?height=265&amp;theme-id=light&amp;default-tab=html,result">See the Pen JS-p2-07-Modifying the document-ex4 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	لاحظ هنا أن النص أُضيف بمثابة "نصٍ" وليس بمثابة شيفرة HTML، حيث تظهر التسلسلات التهريبية مثل <code>&lt;</code> و<code>&gt;</code>. وبالتالي تصبح شيفرة HTML النهائية كالآتي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5648_23" style="">
<span class="tag">&lt;p&gt;</span><span class="pln">Hello</span><span class="tag">&lt;/p&gt;</span><span class="pln">
</span><span class="tag">&lt;hr&gt;</span><span class="pln">
</span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"div"</span><span class="tag">&gt;&lt;/div&gt;</span></pre>

<p>
	وبعبارة أخرى، تُضاف السلاسل النصية بطريقة آمنة كأنها أُضيفت باستعمال الخاصية <code>textContent</code>.
</p>

<p>
	تُستخدم هذه الدوالّ إذا فقط لإضافة عقد DOM أو مقاطع نصية. ولكن ماذا لو أردنا إضافة سلسلةٍ نصيةٍ تحوي شيفرة HTML بما فيها الوسوم وغيرها، مثل ما هو معمول به مع الخاصية <code>innerHTML</code>؟
</p>

<h2>
	الدوالّ insertAdjacentHTML/Text/Element
</h2>

<p>
	والجوابٍ على السؤال السابق، هو استخدام دالّةٍ أخرى متعدّدة الاستعمالات، إنها الدالّة <code>elem.insertAdjacentHTML(where, html)‎</code>. الوسيط الأوّل <code>where</code> للدالّة عبارة عن كلمة رمز (code word) تُحدِّد في أيّ موضع بالضبط من العنصر سيُضاف الوسيط الثاني، وتأخذ هذه الكلمة الرمزواحدةً من القيم التالية:
</p>

<ul>
<li>
		<code>"beforebegin"</code>: إضافة شيفرة HTML مباشرةً قبل العنصر<code>elem</code>.
	</li>
	<li>
		<code>"afterbegin"</code>: إضافة شيفرة HTML في بداية العنصر<code>elem</code>.
	</li>
	<li>
		<code>"beforeend"</code>: إضافة شيفرة HTML في نهاية العنصر<code>elem</code>.
	</li>
	<li>
		<code>"afterend"</code>: إضافة شيفرة HTML مباشرةً بعد العنصر<code>elem</code>.
	</li>
</ul>
<p>
	ويكون الوسيط الثاني <code>html</code> للدالّة عبارة عن سلسلة نصية تُضاف على شكل شيفرة HTML. لاحظ المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5648_25" style="">
<span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"div"</span><span class="tag">&gt;&lt;/div&gt;</span><span class="pln">
</span><span class="tag">&lt;script&gt;</span><span class="pln">
  div</span><span class="pun">.</span><span class="pln">insertAdjacentHTML</span><span class="pun">(</span><span class="str">'beforebegin'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'&lt;p&gt;Hello&lt;/p&gt;'</span><span class="pun">);</span><span class="pln">
  div</span><span class="pun">.</span><span class="pln">insertAdjacentHTML</span><span class="pun">(</span><span class="str">'afterend'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'&lt;p&gt;Bye&lt;/p&gt;'</span><span class="pun">);</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-07-Modifying the document-ex5" src="https://codepen.io/Hsoub/embed/eYBOQeO?height=265&amp;theme-id=light&amp;default-tab=html,result">See the Pen JS-p2-07-Modifying the document-ex5 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	الذي يولّد الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5648_27" style="">
<span class="tag">&lt;p&gt;</span><span class="pln">Hello</span><span class="tag">&lt;/p&gt;</span><span class="pln">
</span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"div"</span><span class="tag">&gt;&lt;/div&gt;</span><span class="pln">
</span><span class="tag">&lt;p&gt;</span><span class="pln">Bye</span><span class="tag">&lt;/p&gt;</span></pre>

<p>
	كانت هذه هي الطريقة التي تُمكّننا من إضافة شيفرة HTML، أيًّا كانت، للصفحة. وفيما يلي صورة توضيحية لطرائق الإضافة في مختلف المواضع:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="56606" href="https://academy.hsoub.com/uploads/monthly_2021_01/003insertAdjacentHTML.png.ad575451cc4eca5116648ee5a6d87548.png" rel=""><img alt="003insertAdjacentHTML.png" class="ipsImage ipsImage_thumbnailed" data-fileid="56606" data-unique="v0o2xorpt" src="https://academy.hsoub.com/uploads/monthly_2021_01/003insertAdjacentHTML.png.ad575451cc4eca5116648ee5a6d87548.png"></a>
</p>

<p>
	ويمكننا بسهولة ملاحظة أوجه الشبه بين هذه الصورة والصورة التي قبلها، حيث أن مواضع الإضافة هي نفسها لكن هذه الدالّة تُضيف شيفرة HTML في حين تُضيف السابقة عقدًا أو سلاسل نصيةً. ولهذه الدالّة دالّتين "شقيقتين":
</p>

<ul>
<li>
		<code>elem.insertAdjacentText(where, text)‎</code>: لها نفس البنية ولكن السلسلة النصية تُضاف هنا كنص وليس كشيفرة HTML.
	</li>
	<li>
		<code>elem.insertAdjacentElement(where, elem)‎</code>: لها أيضًا نفس البنية ولكنها تُستعمل لإضافة عنصرٍ ما.
	</li>
</ul>
<p>
	وُجدت هاتين الدالّتين فقط لضرورة توحيد البنية، ولكن تُستخدم فقط الدالّة <code>elem.insertAdjacentHTML</code> على أرض الواقع، طالما وُجدت الدوالّ <code>append/prepend/before/after</code> التي تُستخدم لإضافة كلٍّ من العقد والنصوص بالإضافة إلى أنها أقصر من حيث عدد الأحرف.<br>
	وفيما يلي طريقةٌ بديلةٌ لإظهار رسالةٍ ما:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5648_29" style="">
<span class="tag">&lt;style&gt;</span><span class="pln">
</span><span class="pun">.</span><span class="pln">alert </span><span class="pun">{</span><span class="pln">
  padding</span><span class="pun">:</span><span class="pln"> </span><span class="lit">15px</span><span class="pun">;</span><span class="pln">
  border</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1px</span><span class="pln"> solid </span><span class="com">#d6e9c6;</span><span class="pln">
  border</span><span class="pun">-</span><span class="pln">radius</span><span class="pun">:</span><span class="pln"> </span><span class="lit">4px</span><span class="pun">;</span><span class="pln">
  color</span><span class="pun">:</span><span class="pln"> </span><span class="com">#3c763d;</span><span class="pln">
  background</span><span class="pun">-</span><span class="pln">color</span><span class="pun">:</span><span class="pln"> </span><span class="com">#dff0d8;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="tag">&lt;/style&gt;</span><span class="pln">
</span><span class="tag">&lt;script&gt;</span><span class="pln">
  document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">insertAdjacentHTML</span><span class="pun">(</span><span class="str">"afterbegin"</span><span class="pun">,</span><span class="pln"> </span><span class="pun">`&lt;</span><span class="pln">div </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"alert"</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">strong</span><span class="pun">&gt;</span><span class="typ">Hi</span><span class="pln"> there</span><span class="pun">!&lt;/</span><span class="pln">strong</span><span class="pun">&gt;</span><span class="pln"> </span><span class="typ">You</span><span class="str">'</span><span class="pln">ve read an important message</span><span class="pun">.</span><span class="pln">
  </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;`);</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-07-Modifying the document-ex6" src="https://codepen.io/Hsoub/embed/dyObQZv?height=265&amp;theme-id=light&amp;default-tab=html,result">See the Pen JS-p2-07-Modifying the document-ex6 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<h2>
	إزالة/حذف عقدة ما
</h2>

<p>
	اُستحدثت الدالّة <code>node.remove()‎</code> لإزالة/حذف عقدةٍ ما. فلنجعل الرسالة التي أظهرناها في المثال السابق تختفي بعد ثانية واحدة من إظهارها:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5648_31" style="">
<span class="tag">&lt;style&gt;</span><span class="pln">
</span><span class="pun">.</span><span class="pln">alert </span><span class="pun">{</span><span class="pln">
  padding</span><span class="pun">:</span><span class="pln"> </span><span class="lit">15px</span><span class="pun">;</span><span class="pln">
  border</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1px</span><span class="pln"> solid </span><span class="com">#d6e9c6;</span><span class="pln">
  border</span><span class="pun">-</span><span class="pln">radius</span><span class="pun">:</span><span class="pln"> </span><span class="lit">4px</span><span class="pun">;</span><span class="pln">
  color</span><span class="pun">:</span><span class="pln"> </span><span class="com">#3c763d;</span><span class="pln">
  background</span><span class="pun">-</span><span class="pln">color</span><span class="pun">:</span><span class="pln"> </span><span class="com">#dff0d8;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="tag">&lt;/style&gt;</span><span class="pln">

</span><span class="tag">&lt;script&gt;</span><span class="pln">
  let div </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">createElement</span><span class="pun">(</span><span class="str">'div'</span><span class="pun">);</span><span class="pln">
  div</span><span class="pun">.</span><span class="pln">className </span><span class="pun">=</span><span class="pln"> </span><span class="str">"alert"</span><span class="pun">;</span><span class="pln">
  div</span><span class="pun">.</span><span class="pln">innerHTML </span><span class="pun">=</span><span class="pln"> </span><span class="str">"&lt;strong&gt;Hi there!&lt;/strong&gt; You've read an important message."</span><span class="pun">;</span><span class="pln">

  document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">append</span><span class="pun">(</span><span class="pln">div</span><span class="pun">);</span><span class="pln">
  setTimeout</span><span class="pun">(()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> div</span><span class="pun">.</span><span class="pln">remove</span><span class="pun">(),</span><span class="pln"> </span><span class="lit">1000</span><span class="pun">);</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-07-Modifying the document-ex7" src="https://codepen.io/Hsoub/embed/xxRKQpV?height=265&amp;theme-id=light&amp;default-tab=html,result">See the Pen JS-p2-07-Modifying the document-ex7 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	لاحظ هنا أنه لا داعيَ لتحويل عنصرٍ ما من الموضع الذي كان فيه إذا أردت وضعه في مكان آخر، <strong>هذا لأنّ كافة دوالّ الإضافة تُحوِّل آليا العنصر من مكانه السابق.</strong> فلنُحوّل من خلال المثال الآتي موضعي العنصرين التاليين:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5648_33" style="">
<span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"first"</span><span class="tag">&gt;</span><span class="pln">First</span><span class="tag">&lt;/div&gt;</span><span class="pln">
</span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"second"</span><span class="tag">&gt;</span><span class="pln">Second</span><span class="tag">&lt;/div&gt;</span><span class="pln">
</span><span class="tag">&lt;script&gt;</span><span class="pln">
  </span><span class="com">// لا داعيَ لمناداة الدالّة remove</span><span class="pln">
  second</span><span class="pun">.</span><span class="pln">after</span><span class="pun">(</span><span class="pln">first</span><span class="pun">);</span><span class="pln"> </span><span class="com">//تُضيف العنصر second بعد العنصر first</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-07-Modifying the document-ex8" src="https://codepen.io/Hsoub/embed/wvowQpx?height=265&amp;theme-id=light&amp;default-tab=html,result">See the Pen JS-p2-07-Modifying the document-ex8 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<h2>
	نسخ العُقد باستعمال الدالة <code>cloneNode</code>
</h2>

<p>
	كيف يمكننا إضافة رسالة مطابقة للرسالة السابقة؟ نستطيع إنشاء دالّة ووضع الشيفرة بداخلها، ولكن هناك طريقة بديلة تنسخ العقدة <code>div</code> وتعدّل النص المتضمّن بداخلها (إن أردنا ذلك). وتسمح لنا هذه الطريقة باختصار الوقت والجهد سيما لو كانت شيفرة العنصر محلّ النسخ طويلةً بعض الشيء.
</p>

<p>
	تُنشِئ الدالّة <code>elem.cloneNode(true)‎</code> عند مناداتها نسخةً كاملةً للعنصر، بما فيه من سمات وتوابع (العناصر الوليدة). أما إذا نادينا الدالّة <code>elem.cloneNode(false)‎</code>- مع تغيير الوسيط من <code>true</code> إلى <code>false</code>- تُنشِئ الدالّة العنصر وحده دون العناصر التابعة له (العناصر الوليدة).
</p>

<p>
	وهذا مثال عن نسخ الرسالة:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5648_35" style="">
<span class="tag">&lt;style&gt;</span><span class="pln">
</span><span class="pun">.</span><span class="pln">alert </span><span class="pun">{</span><span class="pln">
  padding</span><span class="pun">:</span><span class="pln"> </span><span class="lit">15px</span><span class="pun">;</span><span class="pln">
  border</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1px</span><span class="pln"> solid </span><span class="com">#d6e9c6;</span><span class="pln">
  border</span><span class="pun">-</span><span class="pln">radius</span><span class="pun">:</span><span class="pln"> </span><span class="lit">4px</span><span class="pun">;</span><span class="pln">
  color</span><span class="pun">:</span><span class="pln"> </span><span class="com">#3c763d;</span><span class="pln">
  background</span><span class="pun">-</span><span class="pln">color</span><span class="pun">:</span><span class="pln"> </span><span class="com">#dff0d8;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="tag">&lt;/style&gt;</span><span class="pln">

</span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"alert"</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"div"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;strong&gt;</span><span class="pln">Hi there!</span><span class="tag">&lt;/strong&gt;</span><span class="pln"> You've read an important message.
</span><span class="tag">&lt;/div&gt;</span><span class="pln">

</span><span class="tag">&lt;script&gt;</span><span class="pln">
  let div2 </span><span class="pun">=</span><span class="pln"> div</span><span class="pun">.</span><span class="pln">cloneNode</span><span class="pun">(</span><span class="kwd">true</span><span class="pun">);</span><span class="pln"> </span><span class="com">// نسخ الرسالة </span><span class="pln">
  div2</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">'strong'</span><span class="pun">).</span><span class="pln">innerHTML </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Bye there!'</span><span class="pun">;</span><span class="pln"> </span><span class="com">// تغيير محتوى الرسالة المنسوخة </span><span class="pln">

  div</span><span class="pun">.</span><span class="pln">after</span><span class="pun">(</span><span class="pln">div2</span><span class="pun">);</span><span class="pln"> </span><span class="com">//  إظهار النسخة بعد الحاوية الأولى</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-07-Modifying the document-ex9" src="https://codepen.io/Hsoub/embed/rNWBQJa?height=265&amp;theme-id=light&amp;default-tab=html,result">See the Pen JS-p2-07-Modifying the document-ex9 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<h2>
	العقدة الخاصة <code>DocumentFragment</code>
</h2>

<p>
	تُعدّ <code>DocumentFragment</code> عقدة DOM خاصة تُستعمل كمُغلِّف (wrapper) لتمرير قوائم تحوي عددًا من العقد. ويمكننا إضافة عقدٍ لها باستعمال الدالّة append، ولكن عند إضافتها هي (أي العقدة الخاصة <code>DocumentFragment</code>) في موضعٍ ما، يكون محتواها هو ما يُضاف في هذا الموضع بدلا عنها.
</p>

<p>
	تُنشِئ الدالّة <code>getListContent</code> في هذا المثال مقطعا يتضمّن عناصر <code>&lt;li&gt;</code> تُضاف لاحقا إلى العنصر <code>&lt;ul&gt;</code>:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5648_37" style="">
<span class="tag">&lt;ul</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"ul"</span><span class="tag">&gt;&lt;/ul&gt;</span><span class="pln">
</span><span class="tag">&lt;script&gt;</span><span class="pln">
</span><span class="kwd">function</span><span class="pln"> getListContent</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  let fragment </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">DocumentFragment</span><span class="pun">();</span><span class="pln">
  </span><span class="kwd">for</span><span class="pun">(</span><span class="pln">let i</span><span class="pun">=</span><span class="lit">1</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">&lt;=</span><span class="lit">3</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let li </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">createElement</span><span class="pun">(</span><span class="str">'li'</span><span class="pun">);</span><span class="pln">
    li</span><span class="pun">.</span><span class="pln">append</span><span class="pun">(</span><span class="pln">i</span><span class="pun">);</span><span class="pln">
    fragment</span><span class="pun">.</span><span class="pln">append</span><span class="pun">(</span><span class="pln">li</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> fragment</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
ul</span><span class="pun">.</span><span class="pln">append</span><span class="pun">(</span><span class="pln">getListContent</span><span class="pun">());</span><span class="pln"> </span><span class="com">// (*)</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-07-Modifying the document-ex10" src="https://codepen.io/Hsoub/embed/RwobqQj?height=265&amp;theme-id=light&amp;default-tab=html,result">See the Pen JS-p2-07-Modifying the document-ex10 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	لاحظ هنا في السطر الأخير الموسوم بالرمز (*) أنّنا أضفنا العقدة الخاصة <code>DocumentFragment</code> باستعمال الدالّة <code>append</code> (التي تضيف عنصرًا في نهاية عنصرٍ آخر) لكنها تخلّلت الشيفرة فحصلنا على البنية التالية:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5648_39" style="">
<span class="tag">&lt;ul&gt;</span><span class="pln">
  </span><span class="tag">&lt;li&gt;</span><span class="pln">1</span><span class="tag">&lt;/li&gt;</span><span class="pln">
  </span><span class="tag">&lt;li&gt;</span><span class="pln">2</span><span class="tag">&lt;/li&gt;</span><span class="pln">
  </span><span class="tag">&lt;li&gt;</span><span class="pln">3</span><span class="tag">&lt;/li&gt;</span><span class="pln">
</span><span class="tag">&lt;/ul&gt;</span></pre>

<p>
	ونادرًا ما تُستخدم عقدة DOM الخاصية <code>DocumentFragment</code>، ذلك لأنه لا يوجد سببٌ يحملنا على إضافة عنصرٍ أو عناصرَ إلى عقدة من نوعٍ خاصٍ في حين يمكننا وضعه/وضعها في مصفوفة من العقد كالآتي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5648_41" style="">
<span class="tag">&lt;ul</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"ul"</span><span class="tag">&gt;&lt;/ul&gt;</span><span class="pln">

</span><span class="tag">&lt;script&gt;</span><span class="pln">
</span><span class="kwd">function</span><span class="pln"> getListContent</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  let result </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[];</span><span class="pln">

  </span><span class="kwd">for</span><span class="pun">(</span><span class="pln">let i</span><span class="pun">=</span><span class="lit">1</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">&lt;=</span><span class="lit">3</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let li </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">createElement</span><span class="pun">(</span><span class="str">'li'</span><span class="pun">);</span><span class="pln">
    li</span><span class="pun">.</span><span class="pln">append</span><span class="pun">(</span><span class="pln">i</span><span class="pun">);</span><span class="pln">
    result</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="pln">li</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> result</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

ul</span><span class="pun">.</span><span class="pln">append</span><span class="pun">(...</span><span class="pln">getListContent</span><span class="pun">());</span><span class="pln"> 
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-07-Modifying the document-ex11" src="https://codepen.io/Hsoub/embed/jOVNQZJ?height=265&amp;theme-id=light&amp;default-tab=html,result">See the Pen JS-p2-07-Modifying the document-ex11 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	أتينا على ذكر العقدة الخاصة <code>DocumentFragment</code> لأنها تندرج ضمن بعض المفاهيم، كالعنصر <a href="https://javascript.info/template-element" rel="external nofollow">template</a> (أي القالب) مثلا، التي سنتطرّق إليها لاحقا.
</p>

<h2>
	دوال الإضافة والحذف على الطريقة القديمة
</h2>

<p>
	<strong>ملاحظة</strong>: تساعد هذه المعلومة على فهم الشيفرات القديمة ولكنك لن تحتاج إليها أثناء التطوير باستعمال الطرائق العصرية. تَضمّ لغة جافاسكربت أيضًا دوالًا قديمةً تُطبّق على كائنات DOM والتي مازالت موجودة لضرورة التأريخ. تعود هذه الدوالّ إلى زمنٍ بعيدٍ جدًا ولا نحتاج لاستعمالها في الوقت الحالي طالما وَضعت لغة جافاسكربت بين أيدينا دوالًا أكثر مرونة مثل الدوالّ:
</p>

<ul>
<li>
		<code>append</code>
	</li>
	<li>
		<code>prepend</code>
	</li>
	<li>
		before
	</li>
	<li>
		<code>after</code>
	</li>
	<li>
		<code>remove</code>
	</li>
	<li>
		<code>replaceWith</code>
	</li>
</ul>
<p>
	السبب الوحيد الذي جعلنا نذكر لك هنا هذه الدوالّ هو أنك يمكن أن تصادفها في الكثير من السكربتات القديمة.
</p>

<h3>
	الدالة <code>appendChild‎</code>
</h3>

<p>
	تضيف الدالّة <code>parentElem.appendChild(node)‎</code> العقدة <code>node</code> كآخر عنصرٍ وليدٍ للعنصر parentElem. سنضيف في المثال التالي عنصرًا جديدًا <code>&lt;li&gt;</code> في نهاية العنصر الوالد <code>&lt;ol&gt;</code>:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5648_43" style="">
<span class="tag">&lt;ol</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"list"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;li&gt;</span><span class="pln">0</span><span class="tag">&lt;/li&gt;</span><span class="pln">
  </span><span class="tag">&lt;li&gt;</span><span class="pln">1</span><span class="tag">&lt;/li&gt;</span><span class="pln">
  </span><span class="tag">&lt;li&gt;</span><span class="pln">2</span><span class="tag">&lt;/li&gt;</span><span class="pln">
</span><span class="tag">&lt;/ol&gt;</span><span class="pln">

</span><span class="tag">&lt;script&gt;</span><span class="pln">
  let newLi </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">createElement</span><span class="pun">(</span><span class="str">'li'</span><span class="pun">);</span><span class="pln">
  newLi</span><span class="pun">.</span><span class="pln">innerHTML </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Hello, world!'</span><span class="pun">;</span><span class="pln">

  list</span><span class="pun">.</span><span class="pln">appendChild</span><span class="pun">(</span><span class="pln">newLi</span><span class="pun">);</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-07-Modifying the document-ex12" src="https://codepen.io/Hsoub/embed/wvowQmE?height=265&amp;theme-id=light&amp;default-tab=html,result">See the Pen JS-p2-07-Modifying the document-ex12 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<h3>
	الدالة <code>insertBefore</code>
</h3>

<p>
	وتضيف الدالّة <code>parentElem.insertBefore(node, nextSibling)‎</code> العقدة <code>node</code> قبل العقدة <code>nextSibling</code> ضمن العقدة <code>parentElem</code>.
</p>

<p>
	تُضيف الشيفرة التالية عنصرًا جديدًا للقائمة <code>&lt;ol&gt;</code> مباشرة قبل العنصر<code>&lt;li&gt;</code> الثاني في القائمة:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5648_45" style="">
<span class="tag">&lt;ol</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"list"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;li&gt;</span><span class="pln">0</span><span class="tag">&lt;/li&gt;</span><span class="pln">
  </span><span class="tag">&lt;li&gt;</span><span class="pln">1</span><span class="tag">&lt;/li&gt;</span><span class="pln">
  </span><span class="tag">&lt;li&gt;</span><span class="pln">2</span><span class="tag">&lt;/li&gt;</span><span class="pln">
</span><span class="tag">&lt;/ol&gt;</span><span class="pln">
</span><span class="tag">&lt;script&gt;</span><span class="pln">
  let newLi </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">createElement</span><span class="pun">(</span><span class="str">'li'</span><span class="pun">);</span><span class="pln">
  newLi</span><span class="pun">.</span><span class="pln">innerHTML </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Hello, world!'</span><span class="pun">;</span><span class="pln">

  list</span><span class="pun">.</span><span class="pln">insertBefore</span><span class="pun">(</span><span class="pln">newLi</span><span class="pun">,</span><span class="pln"> list</span><span class="pun">.</span><span class="pln">children</span><span class="pun">[</span><span class="lit">1</span><span class="pun">]);</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-07-Modifying the document-ex13" src="https://codepen.io/Hsoub/embed/WNoeYyP?height=265&amp;theme-id=light&amp;default-tab=html,result">See the Pen JS-p2-07-Modifying the document-ex13 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	يمكننا إضافة العقدة <code>newLi</code> في المرتبة الأولى كالآتي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5648_47" style="">
<span class="pln">list</span><span class="pun">.</span><span class="pln">insertBefore</span><span class="pun">(</span><span class="pln">newLi</span><span class="pun">,</span><span class="pln"> list</span><span class="pun">.</span><span class="pln">firstChild</span><span class="pun">);</span></pre>

<h3>
	الدالة <code>replaceWith</code>
</h3>

<p>
	تَستبدلُ هذه الدالّة العقدة <code>node</code> بالعقدة <code>oldChild</code> التي تُعدّ وليدة العقدة <code>parentElem</code>.
</p>

<h3>
	الدالة <code>removeChild</code>
</h3>

<p>
	تحذِف هذه الدالّة العقدة <code>node</code> من العقدة <code>parentElem</code> (حيث نفترض هنا أن العقدة <code>node</code> وليدة العقدة <code>parentElem</code>).
</p>

<p>
	يُحذَف العنصر الأول <code>&lt;li&gt;</code> من القائمة <code>&lt;ol&gt;</code> في المثال الموالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5648_49" style="">
<span class="tag">&lt;ol</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"list"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;li&gt;</span><span class="pln">0</span><span class="tag">&lt;/li&gt;</span><span class="pln">
  </span><span class="tag">&lt;li&gt;</span><span class="pln">1</span><span class="tag">&lt;/li&gt;</span><span class="pln">
  </span><span class="tag">&lt;li&gt;</span><span class="pln">2</span><span class="tag">&lt;/li&gt;</span><span class="pln">
</span><span class="tag">&lt;/ol&gt;</span><span class="pln">

</span><span class="tag">&lt;script&gt;</span><span class="pln">
  let li </span><span class="pun">=</span><span class="pln"> list</span><span class="pun">.</span><span class="pln">firstElementChild</span><span class="pun">;</span><span class="pln">
  list</span><span class="pun">.</span><span class="pln">removeChild</span><span class="pun">(</span><span class="pln">li</span><span class="pun">);</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-07-Modifying the document-ex14" src="https://codepen.io/Hsoub/embed/rNWBQrV?height=265&amp;theme-id=light&amp;default-tab=html,result">See the Pen JS-p2-07-Modifying the document-ex14 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	تكون مخرجات (output) هذه الدوالّ عبارة عن عُقد (العقد التي حُذفت/التي أُضيفت)، حيث تُوّلِد الدالّة <code>parentElement.appendChild(node)‎</code> عقدةً ولكن غالبًا ما لا تُستعمل القيمة التي توّلدت من مناداة هذه الدالّة، نحتاج فقط إلى تطبيق الدالّة/تنفيذها.
</p>

<h2>
	نبذة عن الدالة "document.write"
</h2>

<p>
	هناك أيضا الدالّة <code>document.write</code>، وهي دالّة قديمة جدًا تُستخدم لإضافة جزءٍ ما لصفحة الويب، وبنيتها كالآتي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5648_51" style="">
<span class="tag">&lt;p&gt;</span><span class="pln">Somewhere in the page...</span><span class="tag">&lt;/p&gt;</span><span class="pln">
</span><span class="tag">&lt;script&gt;</span><span class="pln">
  document</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="str">'&lt;b&gt;Hello from JS&lt;/b&gt;'</span><span class="pun">);</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span><span class="pln">
</span><span class="tag">&lt;p&gt;</span><span class="pln">The end</span><span class="tag">&lt;/p&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-07-Modifying the document-ex15" src="https://codepen.io/Hsoub/embed/VwmZVBz?height=265&amp;theme-id=light&amp;default-tab=html,result">See the Pen JS-p2-07-Modifying the document-ex15 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	تؤدي مناداة الدالّة <code>document.write(html)‎</code> إلى كتابة الشيفرة <code>html</code> في الصفحة 'آنذاك وفي هذا الموضع بالضبط'. وبذلك تُولَّد السلسلة النصية <code>html</code> بطريقة ديناميكية (آنية) مرنة. يمكن إذًا استعمال لغة جافاسكربت لإنشاء وكتابة صفحة ويب كاملة.
</p>

<p>
	اِستُحدثت هذه الدالّة في وقت لم تكن فيه كائنات DOM موجودة ولم تكن هناك معايير أيضًا….إلخ، أي منذ زمنٍ بعيدٍ جدًا، ومازالت 'حيّة' ما دام البعض يستعملها لحد الآن في سكربتاته، ولكن نادرًا ما نصادفها في السكربتات العصرية الدارجة حاليا، نظرًا لمحدوديتها في الجوانب التالية:
</p>

<p>
	<strong>تُنفَّذ مناداة الدالّة <code>document.write</code> فقط أثناء تحميل الصفحة</strong> وفي حال نُوديَت بعد ذلك، يُحذف محتوى الصفحة كما في المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5648_53" style="">
<span class="tag">&lt;p&gt;</span><span class="pln">After one second the contents of this page will be replaced...</span><span class="tag">&lt;/p&gt;</span><span class="pln">
</span><span class="tag">&lt;script&gt;</span><span class="pln">
  </span><span class="com">// مناداة الدالّة document.write بعد مرور ثانية واحدة </span><span class="pln">
  </span><span class="com">// أي بعد تحميل الصفحة، فتَحذِف هذه الدالّة المحتوى الأصلي للصفحة </span><span class="pln">
  setTimeout</span><span class="pun">(()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="str">'&lt;b&gt;...By this.&lt;/b&gt;'</span><span class="pun">),</span><span class="pln"> </span><span class="lit">1000</span><span class="pun">);</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-07-Modifying the document-ex16" src="https://codepen.io/Hsoub/embed/preview/xxRKQaE?height=265&amp;theme-id=light&amp;default-tab=html,result">See the Pen JS-p2-07-Modifying the document-ex16 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	لا ينبغي إذًا استعمال هذه الدالّة بعد تحميل الصفحة، على عكس غيرها من دوالّ DOM التي تحدثنا عنها سابقا.
</p>

<p>
	تحدثنا عن الجانب السلبي لهذه الدالّة، لكنها تملك جانبا إيجابيًا أيضًا؛ فمن وجهة نظر تقنية، وفي حال ما نوديت الدالّة <code>document.write</code> أثناء تحليل/قراءة المتصفّح لشيفرة HTML تدريجيا، وكتبت الدالّة بعض الأسطر، يَعتبر المتصفّح أن هذه الأسطر كانت موجودةً منذ البداية في شيفرة HTML، يُسرِّع ذلك كثيرًا من عملية القراءة حيث لا تشمل هذه العملية أيّ تعديلات على DOM، فتكتب الدالّة مباشرةً على الصفحة قبل أن يُنشَأ نموذج تمثيل المستند ككائن.
</p>

<p>
	فإذا أردنا مثلا إضافة سلسلةٍ كبيرةٍ تحوي شيفرة HTML بطريقة ديناميكية في مرحلة تحميل الصفحة، وكان عامل السرعة يصنع الفارق بالنسبة لنا، يمكن أن تكون هذه الطريقة فعالة جدًا. ولكننا نادرًا ما نصادف هذه السيناريوهات على أرض الواقع. بل غالبا ما نصادف هذه الدالّة في بعض السكربتات القديمة (سكربتات كُتبت في وقت لم تكن تُستعمل هذه الدالّة لأغراضٍ كهذه).
</p>

<h2>
	الخلاصة
</h2>

<ul>
<li>
		الدوال التي تُستخدم في إنشاء عقدٍ جديدةٍ هي:
		<ul>
<li>
				<code>document.createElement(tag)‎</code>: تُنشِئ عنصرًا بناءً على الوسم <code>tag</code>.
			</li>
			<li>
				<code>document.createTextNode(value)‎</code>: تُنشِئ عقدةً نصيةً (نادرًا ما تُستخدم).
			</li>
			<li>
				<code>elem.cloneNode(deep)‎</code>: تنسخ العنصر، مع كل توابعه (أي العناصر الوليدة) إذا كانت قيمة المعامل <code>deep</code> تُساوي <code>true</code>.
			</li>
		</ul>
</li>
	<li>
		الدوالّ التي تستخدم للإضافة والحذف هي:
		<ul>
<li>
				<code>node.append(...nodes or strings)‎</code>: تُضيف عقدة أو سلسلة نصية في نهاية العقدة <code>node</code>. -<code>node.prepend(...nodes or strings)‎</code>: تُضيف عقدة أو سلسلة نصية في بداية العقدة <code>node</code>. -<code>node.before(...nodes or strings)‎</code>: تُضيف عقدة أو سلسلة نصية مباشرة قبل العقدة <code>node</code>. -<code>node.after(...nodes or strings)‎</code>: تُضيف عقدة أو سلسلة نصية مباشرة بعد العقدة <code>node</code>. -<code>node.replaceWith(...nodes or strings)‎</code>: تستبدل بالعقدة <code>node</code> ما مُرِّر إليها من عقدة/عقد أو محتوى نصي. -<code>node.remove()‎</code>: تحذف العقدة <code>node</code>.
			</li>
		</ul>
</li>
</ul>
<p>
	وهي تُضيف السلاسل النصية كنص وليس كشيفرة HTML.
</p>

<ul>
<li>
		الدوالّ القديمة هي:
		<ul>
<li>
				<code>rent.appendChild(node)‎</code>
			</li>
			<li>
				<code>parent.insertBefore(node, nextSibling)‎</code>
			</li>
			<li>
				<code>parent.removeChild(node)‎</code>
			</li>
			<li>
				<code>parent.replaceChild(newElem, node)‎</code>
			</li>
		</ul>
</li>
</ul>
<p>
	وتكون مُخرجات (output) هذه الدوالّ عبارة عن عُقد.
</p>

<ul>
<li>
		تضيف الدالّة <code>elem.insertAdjacentHTML(where, html)‎</code> شيفرة HTML، التي تُمرّر لها عبر الوسيط <code>html</code>، في المواضع التالية بناءً على قيمة الوسيط <code>where</code>:
	</li>
	<li>
		<code>"beforebegin"</code>: تُضاف الشيفرة <code>html</code> مباشرة قبل العنصر <code>elem</code>.
	</li>
	<li>
		<code>"afterbegin"</code>: تُضاف الشيفرة <code>html</code> في بداية العنصر <code>elem</code>.
	</li>
	<li>
		<code>"beforeend"</code>: تُضاف الشيفرة <code>html</code> في نهاية العنصر <code>elem</code>.
	</li>
	<li>
		<code>"afterend"</code>: تُضاف الشيفرة <code>html</code> مباشرة بعد العنصر <code>elem</code>.
	</li>
	<li>
		هناك أيضًا دوالٌّ مماثلةٌ لها وهي <code>elem.insertAdjacentText</code> و<code>elem.insertAdjacentElement</code> ولكن نادرًا ما تٌستخدم.
	</li>
	<li>
		إذا أردت إضافة شيفرة HTML إلى الصفحة قبل نهاية عملية تحميلها اِستعمل الدالّة <code>document.write(html)‎</code>.<br>
		تؤدي مناداة هذه الدالّة بعد انتهاء عملية تحميل الصفحة إلى مسح محتوى الصفحة، ونُصادفها خاصة في السكربتات القديمة.
	</li>
</ul>
<h2>
	تمارين
</h2>

<h3>
	createTextNode/innerHTML/textContent
</h3>

<p>
	<em>درجة الأهمية: 5</em> لدينا عنصر DOM فارغ يسمّى <code>elem</code> وسلسلة نصية <code>text</code>. حدِّد، من بين التعليمات الثلاث التالية، تلك التي لها نفس الوظيفة.
</p>

<ol>
<li>
		<code>elem.append(document.createTextNode(text))‎</code>
	</li>
	<li>
		<code>elem.innerHTML = text</code>
	</li>
	<li>
		<code>elem.textContent = text</code>
	</li>
</ol>
<h4>
	<strong>الحل</strong>
</h4>

<p>
	التعليمتان 1 و3 لهما نفس الوظيفة، حيث تضيف كلتا التعليمتين السلسلة النصية <code>text</code> للعنصر <code>elem</code> كنص وليس كشيفرة HTML. وفيما يلي مثال على ذلك:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5648_55" style="">
<span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"elem1"</span><span class="tag">&gt;&lt;/div&gt;</span><span class="pln">
</span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"elem2"</span><span class="tag">&gt;&lt;/div&gt;</span><span class="pln">
</span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"elem3"</span><span class="tag">&gt;&lt;/div&gt;</span><span class="pln">
</span><span class="tag">&lt;script&gt;</span><span class="pln">
  let text </span><span class="pun">=</span><span class="pln"> </span><span class="str">'&lt;b&gt;text&lt;/b&gt;'</span><span class="pun">;</span><span class="pln">
  elem1</span><span class="pun">.</span><span class="pln">append</span><span class="pun">(</span><span class="pln">document</span><span class="pun">.</span><span class="pln">createTextNode</span><span class="pun">(</span><span class="pln">text</span><span class="pun">));</span><span class="pln">
  elem2</span><span class="pun">.</span><span class="pln">innerHTML </span><span class="pun">=</span><span class="pln"> text</span><span class="pun">;</span><span class="pln">
  elem3</span><span class="pun">.</span><span class="pln">textContent </span><span class="pun">=</span><span class="pln"> text</span><span class="pun">;</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<hr>
<h3>
	مسح عنصر ما
</h3>

<p>
	<em>درجة الأهمية: 5</em>
</p>

<p>
	أنشئ الدالّة <code>clear(elem)‎</code> التي تحذف محتوى العنصر <code>elem</code> بالكامل.
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5648_57" style="">
<span class="tag">&lt;ol</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"elem"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;li&gt;</span><span class="pln">Hello</span><span class="tag">&lt;/li&gt;</span><span class="pln">
  </span><span class="tag">&lt;li&gt;</span><span class="pln">World</span><span class="tag">&lt;/li&gt;</span><span class="pln">
</span><span class="tag">&lt;/ol&gt;</span><span class="pln">

</span><span class="tag">&lt;script&gt;</span><span class="pln">
  </span><span class="kwd">function</span><span class="pln"> clear</span><span class="pun">(</span><span class="pln">elem</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="com">/*اكتب الشيفرة هنا */</span><span class="pln"> </span><span class="pun">}</span><span class="pln">

  clear</span><span class="pun">(</span><span class="pln">elem</span><span class="pun">);</span><span class="pln"> </span><span class="com">// clears the list</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<h4>
	<strong>الحل</strong>
</h4>

<p>
	فلنبدأ بالحل الذي لا ينبغي أن تقترحه، لأنه ببساطة حلٌ خاطئ.
</p>

<pre class="ipsCode prettyprint lang-lua prettyprinted" id="ips_uid_5648_65" style="">
<span class="kwd">function</span><span class="pln"> clear</span><span class="pun">(</span><span class="pln">elem</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">let</span><span class="pln"> i</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> elem</span><span class="pun">.</span><span class="pln">childNodes</span><span class="pun">.</span><span class="pln">length</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      elem</span><span class="pun">.</span><span class="pln">childNodes</span><span class="pun">[</span><span class="pln">i</span><span class="pun">].</span><span class="pln">remove</span><span class="pun">();</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	طريقة الحل هذه لا تنفع، لأن مناداة الدالّة <code>remove()‎</code> تؤدي إلى تغيير مواضع العُقد ضِمن المجموعة <code>elem.childNodes</code>، فبعد حذف العقدة الأولى مثلا (التي كانت في الموضع 0 من المجموعة) تُسحب المجموعة كاملةً للخلف لتصبح العقدة ذات الموضع 1 مكان العقدة ذات الموضع 0، لكن المؤشر <code>i</code> في الدورة الثانية من الحلقة يأخذ القيمة 1 وبالتالي تُحذف العقدة ذات الموضع 1 وتبقى العقدة ذات الموضع 0 موجودة، وهكذا دواليك. لن تُحذف إذا بعض العناصر من المجموعة. ويحدث نفس الشيء عند استعمال الحلقة <code>for...of</code>.
</p>

<p>
	الحل الصحيح يكون مثلا كالآتي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5648_63" style="">
<span class="kwd">function</span><span class="pln"> clear</span><span class="pun">(</span><span class="pln">elem</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="pln">elem</span><span class="pun">.</span><span class="pln">firstChild</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    elem</span><span class="pun">.</span><span class="pln">firstChild</span><span class="pun">.</span><span class="pln">remove</span><span class="pun">();</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	أو بطريقة أبسط:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5648_67" style="">
<span class="kwd">function</span><span class="pln"> clear</span><span class="pun">(</span><span class="pln">elem</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  elem</span><span class="pun">.</span><span class="pln">innerHTML </span><span class="pun">=</span><span class="pln"> </span><span class="str">''</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<hr>
<h3>
	لماذا لا تختفي السلسلة 'aaa'؟
</h3>

<p>
	<em>درجة الأهمية: 1</em>
</p>

<p>
	عند مناداة الدالّة <code>table.remove()‎</code>، في المثال التالي، يُحذف الجدول من الصفحة ولكن السلسلة 'aaa' تبقى ظاهرة. فلماذا يحدث ذلك؟
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5648_69" style="">
<span class="tag">&lt;table</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"table"</span><span class="tag">&gt;</span><span class="pln">
  aaa
  </span><span class="tag">&lt;tr&gt;</span><span class="pln">
    </span><span class="tag">&lt;td&gt;</span><span class="pln">Test</span><span class="tag">&lt;/td&gt;</span><span class="pln">
  </span><span class="tag">&lt;/tr&gt;</span><span class="pln">
</span><span class="tag">&lt;/table&gt;</span><span class="pln">

</span><span class="tag">&lt;script&gt;</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln">table</span><span class="pun">);</span><span class="pln"> </span><span class="com">// الجدول موجود</span><span class="pln">

  table</span><span class="pun">.</span><span class="pln">remove</span><span class="pun">();</span><span class="pln">
  </span><span class="com">// لماذا مازالت السلسلة 'aaa' ؟ ظاهرة </span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	<strong>الحل</strong>
</p>

<p>
	يعود السبب في حدوث ذلك إلى خطأ في شيفرة HTML لهذا التمرين.
</p>

<p>
	اِعلم أن من مهام المتصفّح تصحيح الأخطاء آليًا. وبما أن المواصفة التقنية تنصّ على أن الجداول لا تضمّ أيّ سلاسل نصية، بل فقط الوسوم الخاصة بالجداول، يُضيف المتصفح السلسلة <code>"aaa"</code> قبل الجدول <code>table</code> مباشرة. وعندما يُحذف الجدول، تبقى السلسلة <code>"aaa"</code> ظاهرة.
</p>

<p>
	للإجابة على سؤال هذا التمرين، يمكنك الإستعانة بعرض نموذج تمثيل المستند ككائن DOM باستعمال المتصفح، وستظهر لك السلسلة <code>"aaa"</code> قبل الجدول <code>table</code>.
</p>

<p>
	تُحدِّد معايير HTML، وبالتفصيل، كيف يُعالِج المتصفح الشيفرة التي تحتوي على أخطاء، ويُعدّ تعامل المتصفح بهذه الطريقة مع الخطأ المتضمَّن في شيفرة HTML لهذا التمرين صحيحا.
</p>

<hr>
<h3>
	إنشاء قائمة
</h3>

<p>
	<em>درجة الأهمية: 4</em> اكتب شيفرة تُنشِئ واجهةً تسمح للمستخدم بإدخال محتوى ما على مراحل وتجمع هذا المحتوى في شكل قائمة. ولكل عنصر من القائمة عليك:
</p>

<ul>
<li>
		مطالبة المستخدِم بإدخال المحتوى باستعمال الدالّة <code>prompt</code>.
	</li>
	<li>
		إنشاء العنصر<code>&lt;li&gt;</code> بناءً على المحتوى الذي أدخله المستخدِم.
	</li>
	<li>
		مواصلة العملية إلى غاية فراغ المستخدِم من إدخال المعطيات (بالضغط على المفتاح <code>esc</code> على لوحة المفاتيح، أو الضغط على زر الالغاء الظاهر على النافذة).
	</li>
</ul>
<p>
	يجب أن تُنشَئ العناصر ديناميكيًا وإذا أدخل المستخدِم وسوم HTML، تُعالَج على أنها نصوص، لا شيفرة HTML.
</p>

<h4>
	<strong>الحل</strong>
</h4>

<p>
	<strong>ملاحظة</strong>: لاحظ استعمال الخاصية <code>textContent</code> لإسناد محتوى للعنصر <code>&lt;li&gt;</code>.
</p>

<p>
	<a href="https://plnkr.co/edit/zXcaZbeJOV11ebxj?p=preview&amp;preview" rel="external nofollow">يمكنك الإطلاع على الحل من هنا</a>
</p>

<hr>
<h3>
	إنشاء شجرة اعتمادًا على كائن
</h3>

<p>
	<em>درجة الأهمية: 5</em>
</p>

<p>
	اكتب الدالّة <code>createTree()‎</code> التي تُنشئ قائمةً متفرعةً من العناصر <code>ul/li</code> بناءً على كائن متفرع:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5648_71" style="">
<span class="pln">let data </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="str">"Fish"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">"trout"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{},</span><span class="pln">
    </span><span class="str">"salmon"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{}</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">

  </span><span class="str">"Tree"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">"Huge"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="str">"sequoia"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{},</span><span class="pln">
      </span><span class="str">"oak"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{}</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
    </span><span class="str">"Flowering"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="str">"apple tree"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{},</span><span class="pln">
      </span><span class="str">"magnolia"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">};</span></pre>

<p>
	وتكون بنيتها كالآتي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5648_73" style="">
<span class="pln">let container </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">'container'</span><span class="pun">);</span><span class="pln">
createTree</span><span class="pun">(</span><span class="pln">container</span><span class="pun">,</span><span class="pln"> data</span><span class="pun">);</span><span class="pln"> </span><span class="com">// تُنشِئ الشجرة بداخل الحاوية ‘container’ </span></pre>

<p>
	على أن تكون النتيجة المتحصل عليها كالآتي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="56607" href="https://academy.hsoub.com/uploads/monthly_2021_01/004nestedTree.png.89b6bc99634b0284378301fc4992a164.png" rel=""><img alt="004nestedTree.png" class="ipsImage ipsImage_thumbnailed" data-fileid="56607" data-unique="kkxim90qz" src="https://academy.hsoub.com/uploads/monthly_2021_01/004nestedTree.png.89b6bc99634b0284378301fc4992a164.png"></a>
</p>

<p>
	اِختر واحدةً من بين الطريقتين التاليتين لحل التمرين:
</p>

<ul>
<li>
		أنشئ الشجرة في شكل شيفرة HTML ثم أسندها للخاصية <code>Container.innerHTML</code> أو
	</li>
	<li>
		أنشئ عُقد الشجرة وأضفها باستعمال دوالّ DOM.
	</li>
</ul>
<p>
	ويُستحسن أن تَحُل التمرين بالطريقين.
</p>

<p>
	<strong>ملاحظة</strong>: لا ينبغي أن تَضمّ الشجرة في أوراقها عناصر إضافية فارغة <code>&lt;ul&gt;&lt;/ul&gt;</code>.
</p>

<h4>
	<strong>الحل</strong>
</h4>

<p>
	<strong>ملاحظة</strong>: أسهل طريقة لتصفح الكائن (المرور بعناصره الواحد تلوى الآخر) تكون باستعمال التعاود (recursion).
</p>

<ol>
<li>
		<a href="https://plnkr.co/edit/PzjPAk9yKHeKkT36?p=preview&amp;preview" rel="external nofollow">حل التمرين باستعمال الخاصية innerHTML</a>
	</li>
	<li>
		<a href="https://plnkr.co/edit/e3TEVqQrm7ZqZkn6?p=preview&amp;prev" rel="external nofollow">حل التمرين باستعمال دوالّ DOM</a>
	</li>
</ol>
<hr>
<h3>
	إظهار العناصر الوليدة لشجرة ما
</h3>

<p>
	<em>درجة الأهمية: 5</em>
</p>

<p>
	لدينا <a href="https://plnkr.co/edit/4lS7jYgTEE9tX3NU?p=preview&amp;preview" rel="external nofollow">هذه الشجرة</a> وهي مبنية على شكل عناصر <code>ul/li</code> متفرعة. اكتب شيفرة تُضيف من خلالها لكل عنصر <code>&lt;li&gt;</code> عدد عناصره الوليدة مع إهمال الأوراق (العُقد التي ليس لها عناصر وليدة)، والنتيجة تكون على الشكل التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="56608" href="https://academy.hsoub.com/uploads/monthly_2021_01/005showDescendants.png.c8b5156352291c91e9b5414be31c7a3a.png" rel=""><img alt="005showDescendants.png" class="ipsImage ipsImage_thumbnailed" data-fileid="56608" data-unique="30j7pv67u" src="https://academy.hsoub.com/uploads/monthly_2021_01/005showDescendants.png.c8b5156352291c91e9b5414be31c7a3a.png"></a>
</p>

<h4>
	<strong>الحل</strong>
</h4>

<p>
	لإضافة نصٍ لكلّ عنصر من العناصر <code>&lt;li&gt;</code> يمكن التعديل على العُقدة النصية <code>data</code>.
</p>

<p>
	<a href="https://plnkr.co/edit/isiACwTrYRL4hA1Q?p=preview&amp;preview" rel="external nofollow">يمكنك الإطلاع على الحل من هنا</a>
</p>

<hr>
<h3>
	إنشاء يومية
</h3>

<p>
	<em>الأهمية:4</em>
</p>

<p>
	اكتب الدالّة <code>createCalendar(elem, year, month)‎</code> التي تُنشئ يومية الشهر <code>month</code> من السنة <code>year</code>، وتسندها للعنصر <code>elem</code>. تكون اليومية على شكل جدول تُمثِّل فيه العناصر <code>&lt;tr&gt;</code> الأسابيع والعناصر <code>&lt;td&gt;</code> الأيام، وتكون خانات السطر الأول عبارة عن عناصر <code>&lt;th&gt;</code> تحوي أسماء أيام الأسبوع مُرتّبةً من الإثنين إلى الأحد. فعلى سبيل المثال، تؤدي مناداة الدالّة <code>createCalendar(cal, 2012, 9)‎</code> إلى إنشاء اليومية التالية وإسنادها للعنصر <code>cal</code>.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="56609" href="https://academy.hsoub.com/uploads/monthly_2021_01/006createCalendar.png.c88f351f535bdcb82f353015e9d5c642.png" rel=""><img alt="006createCalendar.png" class="ipsImage ipsImage_thumbnailed" data-fileid="56609" data-unique="gfsr1ezuf" src="https://academy.hsoub.com/uploads/monthly_2021_01/006createCalendar.png.c88f351f535bdcb82f353015e9d5c642.png"></a>
</p>

<p>
	<strong>ملاحظة</strong>: يكفي في هذه المرحلة إظهار اليومية، لا نحتاج أن تكون تفاعلية.
</p>

<p>
	<a href="https://plnkr.co/edit/HMGrxDjPkb7TmppV?p=preview&amp;preview" rel="external nofollow">يمكنك الإطلاع على شيفرة التمرين من هنا</a>
</p>

<h4>
	<strong>الحل</strong>
</h4>

<p>
	نُنشئ الجدول على شكل سلسلة نصية <code>"&lt;table&gt;....&lt;/table&gt;"</code> ثم نسندها إلى الخاصية <code>innerHTML</code>، باتباع خطوات الخوارزمية التالية:
</p>

<ol>
<li>
		إنشاء خانات السطر الأول من الجدول (table header) باستعمال عناصر<code>&lt;th&gt;</code> تحوي أسماء أيام الأسبوع.
	</li>
	<li>
		إنشاء الكائن<code>date</code> باستعمال الدالّة البانية <code>d=newDate(year, month-1)‎</code> والذي يُمثِّل أول يوم في الشهر <code>month</code> (مع الأخذ في الحسبان أن ترتيب الأشهر في جافاسكربت يبدأ من 0 وليس من 1).
	</li>
	<li>
		ملء الخانات التي تسبق خانة اليوم الأول من الشهر (أي اليوم <code>d.getDay()‎</code>)، والتي تكون فارغة في اليومية، بإضافة عناصر <code>&lt;td&gt;&lt;/td&gt;</code> فارغة للجدول.
	</li>
	<li>
		الانتقال تصاعديا عبر الأيام باستعمال الدالّة <code>d.setDate(d.getDate()+1)‎</code> وإضافة الخانات <code>&lt;td&gt;</code> لليومية مادامت قيمة <code>d.getMonth()‎</code> تشير إلى الشهر نفسه (لم نصل بعد للشهر الموالي). وإذا كان اليوم يوم أحدٍ نضيف سطرًا جديدًا <code>&lt;tr&gt;&lt;/tr&gt;</code>.
	</li>
	<li>
		إذا وصلنا إلى نهاية الشهر، ومازالت في السطر خانات فارغة، نملؤها بعناصر <code>&lt;td&gt;&lt;/td&gt;</code> فارغة لنجعل الجدول مستطيلا.
	</li>
</ol>
<p>
	<a href="https://plnkr.co/edit/8TutdHGPz06kKUQS?p=preview&amp;preview" rel="external nofollow">يمكنك الإطلاع على الحل من هنا</a>
</p>

<hr>
<h3>
	إنشاء ساعة ملونة باستعمال الدالّة <code>setInterval</code>
</h3>

<p>
	<em>الأهمية: 4</em>
</p>

<p>
	أنشئ ساعة ملونة تشبه الساعة في الشكل التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="56610" href="https://academy.hsoub.com/uploads/monthly_2021_01/007coloredClock.png.84f11b6363ed0d66aa40658775bd0f7c.png" rel=""><img alt="007coloredClock.png" class="ipsImage ipsImage_thumbnailed" data-fileid="56610" data-unique="ihlrwsfa6" src="https://academy.hsoub.com/uploads/monthly_2021_01/007coloredClock.png.84f11b6363ed0d66aa40658775bd0f7c.png"></a>
</p>

<p>
	استعمل HTML/CSS للتنسيق، وجافاسكربت فقط لتحديث القيم الزمنية للعناصر.
</p>

<h4>
	<strong>الحل</strong>
</h4>

<p>
	فلنكتب أولا شيفرة التنسيق باستعمال HTML/CSS. نضع كلَّ مكون زمني في حاوية خاصة به (الساعات في حاوية، الدقائق في حاوية أخرى والثواني أيضا في حاوية) ونلونها باستعمال CSS.
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5648_75" style="">
<span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"clock"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"hour"</span><span class="tag">&gt;</span><span class="pln">hh</span><span class="tag">&lt;/span&gt;</span><span class="pln">:</span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"min"</span><span class="tag">&gt;</span><span class="pln">mm</span><span class="tag">&lt;/span&gt;</span><span class="pln">:</span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"sec"</span><span class="tag">&gt;</span><span class="pln">ss</span><span class="tag">&lt;/span&gt;</span><span class="pln">
</span><span class="tag">&lt;/div&gt;</span></pre>

<p>
	تحدِّث الدالّة <code>update()‎</code> الوقت، وتنادي الدالّة <code>setInterval</code> الدالّة <code>update()‎</code> كل ثانية لتحيين الوقت.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5648_77" style="">
<span class="kwd">function</span><span class="pln"> update</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  let clock </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">'clock'</span><span class="pun">);</span><span class="pln">
  let date </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Date</span><span class="pun">();</span><span class="pln"> </span><span class="com">// (*)</span><span class="pln">
  let hours </span><span class="pun">=</span><span class="pln"> date</span><span class="pun">.</span><span class="pln">getHours</span><span class="pun">();</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">hours </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">10</span><span class="pun">)</span><span class="pln"> hours </span><span class="pun">=</span><span class="pln"> </span><span class="str">'0'</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> hours</span><span class="pun">;</span><span class="pln">
  clock</span><span class="pun">.</span><span class="pln">children</span><span class="pun">[</span><span class="lit">0</span><span class="pun">].</span><span class="pln">innerHTML </span><span class="pun">=</span><span class="pln"> hours</span><span class="pun">;</span><span class="pln">

  let minutes </span><span class="pun">=</span><span class="pln"> date</span><span class="pun">.</span><span class="pln">getMinutes</span><span class="pun">();</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">minutes </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">10</span><span class="pun">)</span><span class="pln"> minutes </span><span class="pun">=</span><span class="pln"> </span><span class="str">'0'</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> minutes</span><span class="pun">;</span><span class="pln">
  clock</span><span class="pun">.</span><span class="pln">children</span><span class="pun">[</span><span class="lit">1</span><span class="pun">].</span><span class="pln">innerHTML </span><span class="pun">=</span><span class="pln"> minutes</span><span class="pun">;</span><span class="pln">

  let seconds </span><span class="pun">=</span><span class="pln"> date</span><span class="pun">.</span><span class="pln">getSeconds</span><span class="pun">();</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">seconds </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">10</span><span class="pun">)</span><span class="pln"> seconds </span><span class="pun">=</span><span class="pln"> </span><span class="str">'0'</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> seconds</span><span class="pun">;</span><span class="pln">
  clock</span><span class="pun">.</span><span class="pln">children</span><span class="pun">[</span><span class="lit">2</span><span class="pun">].</span><span class="pln">innerHTML </span><span class="pun">=</span><span class="pln"> seconds</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	نتحقّق في السطر الموسوم بالرمز (*) من الوقت آنيا لأن القيم التي تَنتُج من مناداة الدالّة <code>setInterval</code> غير موثوقة، حيث يمكن أن يكون فيها بعض التأخير. فيما يلي الدوالّ التي تُستعمل لإدارة الساعة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5648_79" style="">
<span class="pln">let timerId</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> clockStart</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="com">// run the clock</span><span class="pln">
  timerId </span><span class="pun">=</span><span class="pln"> setInterval</span><span class="pun">(</span><span class="pln">update</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1000</span><span class="pun">);</span><span class="pln">
  update</span><span class="pun">();</span><span class="pln"> </span><span class="com">// (*)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> clockStop</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  clearInterval</span><span class="pun">(</span><span class="pln">timerId</span><span class="pun">);</span><span class="pln">
  timerId </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لاحظ أن الدالّة <code>update()‎</code>، بالإضافة لكونها مُبرمَجةً لتُنفَّذ دوريًا كلّ ثانية داخل الدالّة <code>clockStart()‎</code>، فهي تُنفَّذُ في السطر الموسوم بالرمز (*) في الحين ولا تنتظر حتى تنادي الدالّة <code>setInterval</code> الدالّة <code>update()‎</code>، وذلك لتفادي بقاء الساعة فارغةً طول مدّة تنفيذ الدالّة<code>setInterval</code> (أي مدّة ثانية واحدة) عند مناداتها أول مرة.
</p>

<p>
	<a href="https://plnkr.co/edit/ZvfbCgJsJ5gFqBpx?p=preview&amp;preview" rel="external nofollow">يمكنك الإطلاع على الحل من هنا</a>
</p>

<hr>
<h3>
	إضافة شيفرة HTML إلى قائمة
</h3>

<p>
	_الأهمية: 5 _
</p>

<p>
	اكتب الشيفرة التي تُضيف المقطع <code>&lt;li&gt;2&lt;/li&gt;&lt;li&gt;3&lt;/li&gt;</code> بين العنصرين <code>&lt;li&gt;</code> فيما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5648_81" style="">
<span class="tag">&lt;ul</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"ul"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;li</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"one"</span><span class="tag">&gt;</span><span class="pln">1</span><span class="tag">&lt;/li&gt;</span><span class="pln">
  </span><span class="tag">&lt;li</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"two"</span><span class="tag">&gt;</span><span class="pln">4</span><span class="tag">&lt;/li&gt;</span><span class="pln">
</span><span class="tag">&lt;/ul&gt;</span></pre>

<h4>
	<strong>الحل</strong>
</h4>

<p>
	تُعدّ الدالّة <code>insertAdjacentHTML</code> أحسن اختيار حين يتعلق الأمر بإضافة شيفرة HTML في موضع ما من الصفحة.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5648_83" style="">
<span class="pln">one</span><span class="pun">.</span><span class="pln">insertAdjacentHTML</span><span class="pun">(</span><span class="str">'afterend'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'&lt;li&gt;2&lt;/li&gt;&lt;li&gt;3&lt;/li&gt;'</span><span class="pun">);</span></pre>

<hr>
<h3>
	فرز جدول ما
</h3>

<p>
	<em>الأهمية: 5</em>
</p>

<p>
	لدينا الجدول التالي (قد يحوي عددًا أكبر من السطور):
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5648_85" style="">
<span class="tag">&lt;table&gt;</span><span class="pln">
</span><span class="tag">&lt;thead&gt;</span><span class="pln">
  </span><span class="tag">&lt;tr&gt;</span><span class="pln">
    </span><span class="tag">&lt;th&gt;</span><span class="pln">Name</span><span class="tag">&lt;/th&gt;&lt;th&gt;</span><span class="pln">Surname</span><span class="tag">&lt;/th&gt;&lt;th&gt;</span><span class="pln">Age</span><span class="tag">&lt;/th&gt;</span><span class="pln">
  </span><span class="tag">&lt;/tr&gt;</span><span class="pln">
</span><span class="tag">&lt;/thead&gt;</span><span class="pln">
</span><span class="tag">&lt;tbody&gt;</span><span class="pln">
  </span><span class="tag">&lt;tr&gt;</span><span class="pln">
    </span><span class="tag">&lt;td&gt;</span><span class="pln">John</span><span class="tag">&lt;/td&gt;&lt;td&gt;</span><span class="pln">Smith</span><span class="tag">&lt;/td&gt;&lt;td&gt;</span><span class="pln">10</span><span class="tag">&lt;/td&gt;</span><span class="pln">
  </span><span class="tag">&lt;/tr&gt;</span><span class="pln">
  </span><span class="tag">&lt;tr&gt;</span><span class="pln">
    </span><span class="tag">&lt;td&gt;</span><span class="pln">Pete</span><span class="tag">&lt;/td&gt;&lt;td&gt;</span><span class="pln">Brown</span><span class="tag">&lt;/td&gt;&lt;td&gt;</span><span class="pln">15</span><span class="tag">&lt;/td&gt;</span><span class="pln">
  </span><span class="tag">&lt;/tr&gt;</span><span class="pln">
  </span><span class="tag">&lt;tr&gt;</span><span class="pln">
    </span><span class="tag">&lt;td&gt;</span><span class="pln">Ann</span><span class="tag">&lt;/td&gt;&lt;td&gt;</span><span class="pln">Lee</span><span class="tag">&lt;/td&gt;&lt;td&gt;</span><span class="pln">5</span><span class="tag">&lt;/td&gt;</span><span class="pln">
  </span><span class="tag">&lt;/tr&gt;</span><span class="pln">
  </span><span class="tag">&lt;tr&gt;</span><span class="pln">
    </span><span class="tag">&lt;td&gt;</span><span class="pln">...</span><span class="tag">&lt;/td&gt;&lt;td&gt;</span><span class="pln">...</span><span class="tag">&lt;/td&gt;&lt;td&gt;</span><span class="pln">...</span><span class="tag">&lt;/td&gt;</span><span class="pln">
  </span><span class="tag">&lt;/tr&gt;</span><span class="pln">
</span><span class="tag">&lt;/tbody&gt;</span><span class="pln">
</span><span class="tag">&lt;/table&gt;</span></pre>

<p>
	اكتب الشيفرة التي تعيدُ ترتيبه ترتيبًا أبجديًا حسب محتوى العمود <code>name</code>.
</p>

<h4>
	<strong>الحل</strong>
</h4>

<p>
	الحل عبارة عن بضعة سطور فقط، ولكننا نحتاج إلى شرح الحيل التي اُستعمِلت فيه. ويكون باتباع خطوات الخوارزمية التالية:
</p>

<ol>
<li>
		استخراج سطور الجدول من العنصر <code>tbody</code>.
	</li>
	<li>
		ترتيبها حسب محتوى العمود الأول <code>name</code> ترتيبًا أبجديًا.
	</li>
	<li>
		إضافة العُقد حسب الترتيب الجديد باستعمال <code>append(sortedRows)‎</code>.
	</li>
</ol>
<p>
	لستَ مضطرًا لحذف العناصر<code>&lt;tr&gt;</code>، عليك فقط إعادة إضافتها حيث تنتقل آليًا من مواضعها الأصلية إلى المواضع الجديدة بعد ترتيبها.
</p>

<p>
	<strong>ملاحظة</strong>: العنصر <code>tbody</code> من الجدول مذكورٌ صراحةً في شيفرة HTML ولكن حتى وإن لم يُذكر صراحةً، فهو دائمًا موجود في بنية DOM.
</p>

<p>
	<a href="https://plnkr.co/edit/5xHStBMfV5AVtoxR?p=preview&amp;preview" rel="external nofollow">يمكنك الإطلاع على الحل من هنا</a>
</p>

<p>
	ترجمة -وبتصرف- للفصل <a href="https://javascript.info/modifying-document" rel="external nofollow">Modifying the document</a> من كتاب <a href="https://javascript.info/ui" rel="external nofollow">Browser: Document, Events, Interfaces</a>
</p>
]]></description><guid isPermaLink="false">1117</guid><pubDate>Sat, 30 Jan 2021 13:07:02 +0000</pubDate></item><item><title>&#x627;&#x644;&#x62A;&#x641;&#x631;&#x64A;&#x642; &#x628;&#x64A;&#x646; &#x627;&#x644;&#x633;&#x645;&#x627;&#x62A; (attributes) &#x641;&#x64A; HTML &#x648;&#x627;&#x644;&#x62E;&#x627;&#x635;&#x64A;&#x627;&#x62A; (properties)  &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A;</title><link>https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%AA%D9%81%D8%B1%D9%8A%D9%82-%D8%A8%D9%8A%D9%86-%D8%A7%D9%84%D8%B3%D9%85%D8%A7%D8%AA-attributes-%D9%81%D9%8A-html-%D9%88%D8%A7%D9%84%D8%AE%D8%A7%D8%B5%D9%8A%D8%A7%D8%AA-properties-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r1116/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_01/6013d5f156557_-.png.6e8eb57f2089e47fe5bc5e9e09819ae2.png" /></p>

<p>
	عندما يُحمِّل المتصفّح الصّفحة، فهو يقرأ/يحلّل شيفرة HTML ويُنشئ من خلالها كائنات DOM. وحين يتعلّق الأمر بالعُقد العناصرية (element nodes)، فإن غالبية سمات HTML المعيارية تصبح خاصيات للكائنات DOM.
</p>

<p>
	فعلى سبيل المثال، إذا كانت السمة كالتالي: <code>&lt;"body id="page&gt;</code>، يكتسب كائن DOM الخاصية <code>"body.id="page</code>. لكن عملية الربط بين السمات والخاصيات لا تتم تقابليا (كلّ سمة لا يقابلها بالضرورة خاصية). فيما يلي ستتعرف على كيفية التمييز بين الْمفهومَيْن، لتتعلم طريقة استخدامهما حين يتطابقان وحين يختلفان.
</p>

<h2>
	خاصيات DOM
</h2>

<p>
	سبق وأن تعرفت على خاصيات نموذج تمثيل المستند ككائن (أي خاصيات DOM) المبنيّة مسبقًا. هناك العديد منها ولكن ذلك لا يمنع المبرمج من إضافة/إنشاء خاصيات أخرى إذا لم تكن الخاصيات المبنيّة مسبقًا كافية لتلبية حاجاته. تُعدّ عُقد DOM كائنات جافاسكربت عادية يمكنك التعديل عليها.
</p>

<p>
	فلننشئ على سبيل المثال خاصيّة جديدة للكائن <code>document.body</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3921_7" style="">
<span class="pln">document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">myData </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Caesar'</span><span class="pun">,</span><span class="pln">
  title</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Imperator'</span><span class="pln">
</span><span class="pun">};</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">myData</span><span class="pun">.</span><span class="pln">title</span><span class="pun">);</span><span class="pln"> </span><span class="com">// Imperator</span></pre>

<div class="codepen" data-default-tab="js,result" data-height="265" data-prefill='{"title":"JS-p2-06-Attributes and properties-ex1","tags":[],"scripts":[],"stylesheets":[]}' data-preview="true" data-slug-hash="vYyBVbK" data-theme-id="light" data-user="Hsoub">
	<pre data-lang="js">
كما يمكن إضافة دالّة أيضًا:</pre>
</div>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4660_6" style="">
<span class="pln">document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">sayTagName </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  alert</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">tagName</span><span class="pun">);</span><span class="pln">
</span><span class="pun">};</span><span class="pln">
document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">sayTagName</span><span class="pun">();</span><span class="pln"> </span><span class="com">// BODY </span><span class="pln">
</span><span class="pun">(قيمة</span><span class="pln"> </span><span class="kwd">this</span><span class="pln"> </span><span class="pun">في</span><span class="pln"> </span><span class="pun">الدالة</span><span class="pln"> </span><span class="pun">هي</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">)</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-06-Attributes and properties-ex2" src="https://codepen.io/Hsoub/embed/preview/ZEBzqwm?height=265&amp;theme-id=light&amp;default-tab=js,result">See the Pen JS-p2-06-Attributes and properties-ex2 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	يمكن أيضًا تعديل النماذج المبنيّة مسبقًا مثل <code>Element.prototype</code> وإضافة دوالّ جديدة تُطبّق على كلّ العناصر.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3921_11" style="">
<span class="typ">Element</span><span class="pun">.</span><span class="pln">prototype</span><span class="pun">.</span><span class="pln">sayHi </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  alert</span><span class="pun">(`</span><span class="typ">Hello</span><span class="pun">,</span><span class="pln"> I</span><span class="str">'</span><span class="pln">m $</span><span class="pun">{</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">tagName</span><span class="pun">}`);</span><span class="pln">
</span><span class="pun">};</span><span class="pln">
document</span><span class="pun">.</span><span class="pln">documentElement</span><span class="pun">.</span><span class="pln">sayHi</span><span class="pun">();</span><span class="pln"> </span><span class="com">// Hello, I'm HTML</span><span class="pln">
document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">sayHi</span><span class="pun">();</span><span class="pln"> </span><span class="com">// Hello, I'm BODY</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-06-Attributes and properties-ex3" src="https://codepen.io/Hsoub/embed/preview/PobYyLm?height=265&amp;theme-id=light&amp;default-tab=js,result">See the Pen JS-p2-06-Attributes and properties-ex3 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	تسلُك خاصيات ودوالّ DOM إذا سلوكًا مماثلًا لسلوك كائنات جافاسكربت العاديّة ويمكنها استقبال أيّ قيمةٍ كانت. فهي تخضع لشرط التمييز بين الحروف الكبيرة والحروف الصغيرة (فنكتب مثلا <code>elem.nodeType</code>، ولا نكتب <code>elem.NodeType</code>).
</p>

<h2>
	سمات HTML
</h2>

<p>
	يمكن أن تملك وسوم HTML سمات، ويتعرف المتصفّح على السمات المعيارية عندما يقرأ الوسوم ويحلّلها لإنشاء خاصيات لكائنات DOM المقابلة لها.
</p>

<p>
	وبذلك، عندما يكون للعنصر السمة <code>id</code> أوأيّ سمة معيارية أخرى، تُنشَأُ الخاصية الموافقة لها. ولكن ذلك لن يحدث إذا كانت الخاصية غير معيارية.
</p>

<p>
	انظر المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3921_13" style="">
<span class="pun">&lt;</span><span class="pln">body id</span><span class="pun">=</span><span class="str">"test"</span><span class="pln"> something</span><span class="pun">=</span><span class="str">"non-standard"</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="pln">script</span><span class="pun">&gt;</span><span class="pln">
    alert</span><span class="pun">(</span><span class="pln">document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">id</span><span class="pun">);</span><span class="pln"> </span><span class="com">// test</span><span class="pln">
    </span><span class="com">// السمة غير المعيارية لا تولّد خاصية مقابلة لها</span><span class="pln">
    alert</span><span class="pun">(</span><span class="pln">document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">something</span><span class="pun">);</span><span class="pln"> </span><span class="com">// undefined</span><span class="pln">
  </span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">body</span><span class="pun">&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-06-Attributes and properties-ex4" src="https://codepen.io/Hsoub/embed/preview/ZEBzqPm?height=265&amp;theme-id=light&amp;default-tab=html,result">See the Pen JS-p2-06-Attributes and properties-ex4 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	لاحظ أن سمةً ما قد تكون معياريةً لعناصر دون غيرها وغير مُعرّفةٍ إذا تعلّق الأمر بعناصر أخرى. فمثلًا تُعدّ السمة <code>"type"</code> سمةً معياريةً للعنصر <code>&lt;input&gt;</code>‏ (<a href="https://html.spec.whatwg.org/#htmlinputelement" rel="external nofollow">HTMLInputElement</a>) وغير معيارية للعنصر <code>&lt;body&gt;</code>‏ (<a href="https://html.spec.whatwg.org/#htmlbodyelement" rel="external nofollow">HTMLBodyElement</a>). وستجد وصفًا للسمات المعيارية في مواصفات صنف كل عنصر.
</p>

<p>
	والمثال التالي يوضّح ذلك:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_3921_15" style="">
<span class="tag">&lt;body</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"body"</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"..."</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"input"</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"text"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;script&gt;</span><span class="pln">
    alert</span><span class="pun">(</span><span class="pln">input</span><span class="pun">.</span><span class="pln">type</span><span class="pun">);</span><span class="pln"> </span><span class="com">// text</span><span class="pln">
    alert</span><span class="pun">(</span><span class="pln">body</span><span class="pun">.</span><span class="pln">type</span><span class="pun">);</span><span class="pln"> </span><span class="com">// undefined</span><span class="pln">
</span><span class="pun">لم</span><span class="pln"> </span><span class="pun">تٌنشأ</span><span class="pln"> </span><span class="pun">خاصية</span><span class="pln"> DOM  </span><span class="pun">لأنها</span><span class="pln"> </span><span class="pun">غير</span><span class="pln"> </span><span class="pun">معيارية</span><span class="pln"> </span><span class="com">//</span><span class="pln">
  </span><span class="tag">&lt;/script&gt;</span><span class="pln">
</span><span class="tag">&lt;/body&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-06-Attributes and properties-ex5" src="https://codepen.io/Hsoub/embed/preview/rNWBqbR?height=265&amp;theme-id=light&amp;default-tab=html,result">See the Pen JS-p2-06-Attributes and properties-ex5 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	وبالتالي إذا كانت السمة غير معيارية، لا تٌنشأ خاصية DOM الموافقة لها. فهل من طريقة تسمح بالوصول إلى هذه السمات؟ بالتأكيد، يمكن الوصول إلى جميع السمات باستعمال الدوالّ التالية:
</p>

<ul>
<li>
		<code>(elem.hasAttribute(name</code>: للتحقّق من وجود السمة.
	</li>
	<li>
		<code>(elem.getAttribute(name</code>: للحصول على قيمة السمة.
	</li>
	<li>
		<code>(elem.setAttribute(name, value</code>: إسناد القيمة <code>value</code> للسمة <code>name</code>.
	</li>
	<li>
		<code>(elem.removeAttribute(name</code>: حذف السمة.
	</li>
</ul>
<p>
	وتُستخدم هذه الدوالّ مع السمات غير المعيارية كما هي مكتوبة بالضبط في شيفرة HTML. يمكن أيضًا قراءة كافة السمات باستعمال <code>elem.attributes</code>؛ وهو مجموعة من الكائنات التي تنتمي إلى صنف <a href="https://dom.spec.whatwg.org/#attr" rel="external nofollow"><code>Attr</code></a> المبني مسبقًا، تملك خاصيتي الاسم <code>name</code> والقيمة <code>value</code>.
</p>

<p>
	فيما يلي عرض لكيفية قراءة سمة غير معيارية:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_3921_17" style="">
<span class="tag">&lt;body</span><span class="pln"> </span><span class="atn">something</span><span class="pun">=</span><span class="atv">"non-standard"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;script&gt;</span><span class="pln">
    alert</span><span class="pun">(</span><span class="pln">document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">getAttribute</span><span class="pun">(</span><span class="str">'something'</span><span class="pun">));</span><span class="pln"> </span><span class="com">// non-standard</span><span class="pln">
  </span><span class="tag">&lt;/script&gt;</span><span class="pln">
</span><span class="tag">&lt;/body&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-06-Attributes and properties-ex6" src="https://codepen.io/Hsoub/embed/preview/GRNKYaW?height=265&amp;theme-id=light&amp;default-tab=html,result">See the Pen JS-p2-06-Attributes and properties-ex6 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	تملك سمات HTML الميزات التالية:
</p>

<ul>
<li>
		لا تخضع لشرط التمييز بين الحروف الصغيرة والحروف الكبيرة (<code>id</code> هو نفسه <code>ID</code>).
	</li>
	<li>
		تكون قيم هذه السمات دائما من نوع سلاسل نصّية (أي من النوع string).
	</li>
</ul>
<p>
	فيما يلي عرضٌ موسّعٌ يوضّح طريقة التعامل مع السمات:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_3921_19" style="">
<span class="tag">&lt;body&gt;</span><span class="pln">
  </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"elem"</span><span class="pln"> </span><span class="atn">about</span><span class="pun">=</span><span class="atv">"Elephant"</span><span class="tag">&gt;&lt;/div&gt;</span><span class="pln">
  </span><span class="tag">&lt;script&gt;</span><span class="pln">
    alert</span><span class="pun">(</span><span class="pln"> elem</span><span class="pun">.</span><span class="pln">getAttribute</span><span class="pun">(</span><span class="str">'About'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// (1) 'Elephant', جلب</span><span class="pln">
    elem</span><span class="pun">.</span><span class="pln">setAttribute</span><span class="pun">(</span><span class="str">'Test'</span><span class="pun">,</span><span class="pln"> </span><span class="lit">123</span><span class="pun">);</span><span class="pln"> </span><span class="com">// (2), ضبط</span><span class="pln">
    alert</span><span class="pun">(</span><span class="pln"> elem</span><span class="pun">.</span><span class="pln">outerHTML </span><span class="pun">);</span><span class="pln"> </span><span class="com">// (3), التحقق من وجود السمة في شيفرة HTML (نعم)</span><span class="pln">
    </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let attr of elem</span><span class="pun">.</span><span class="pln">attributes</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="com">// (4) عرض القائمة كاملة</span><span class="pln">
      alert</span><span class="pun">(</span><span class="pln"> </span><span class="pun">`</span><span class="pln">$</span><span class="pun">{</span><span class="pln">attr</span><span class="pun">.</span><span class="pln">name</span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">attr</span><span class="pun">.</span><span class="pln">value</span><span class="pun">}`</span><span class="pln"> </span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="tag">&lt;/script&gt;</span><span class="pln">
</span><span class="tag">&lt;/body&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-06-Attributes and properties-ex7" src="https://codepen.io/Hsoub/embed/preview/yLVBRWR?height=265&amp;theme-id=light&amp;default-tab=html,result">See the Pen JS-p2-06-Attributes and properties-ex7 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	لاحظ ما يلي: (1).<code>('getAttribute('About</code>: الحرف الأول من كلمة About هو حرف كبير مع أنه صغير في شيفرة HTML. هذا لا يُسبّب أيّ مشكلةٍ طالما أن أسماء السمات لا تخضع لشرط التمييز بين الحروف الكبيرة والحروف الصغيرة. (2). يمكن إسناد قيمة من أيّ نوعٍ كان للسمة، ولكن هذه القيمة تصبح سلسلةً نصّيةً. قيمة السمة <code>Test</code> اذًا هنا هي <code>"123"</code>. (3). تظهر كافة السمات بما فيها تلك التي أضفناها (أي غير المعيارية مثل تلك التي كانت موجودة في الشيفرة كالسمة 'About'، وتلك التي أضفناها كالسمة 'Test') في <code>outerHTML</code>. (4). تُعدّ مجموعة السمات <code>attributes</code> قابلة للتمرير ضمن حلقة تكرار، وتضمّ كافة سمات العنصر، المعيارية منها وغير المعيارية، في شكل كائنات تملك خاصيتي الاسم <code>name</code> والقيمة <code>value</code>.
</p>

<h2>
	المزامنة (synchronization) بين الخاصية والسمة
</h2>

<p>
	حين تتغيّر سمة معيارية ما، يجري تحديث الخاصية الموافقة لها آليًا والعكس كذلك صحيح (ما عدا في بعض الحالات الاستثنائية). عُدّلت في المثال الموالي السمة <code>"id"</code>، فلاحظ أن ذلك أدّى الى تعديل الخاصية أيضًا. وحدث الشّيء نفسه في المثال العكسي الذي جاء بعده، حيث عُدّلت الخاصية وهو ما أدّى إلى تعديل السمة آليًا.
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_3921_21" style="">
<span class="tag">&lt;input&gt;</span><span class="pln">
</span><span class="tag">&lt;script&gt;</span><span class="pln">
  let input </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">'input'</span><span class="pun">);</span><span class="pln">
  </span><span class="com">// سمة =&gt; خاصّية</span><span class="pln">
  input</span><span class="pun">.</span><span class="pln">setAttribute</span><span class="pun">(</span><span class="str">'id'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'id'</span><span class="pun">);</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln">input</span><span class="pun">.</span><span class="pln">id</span><span class="pun">);</span><span class="pln"> </span><span class="com">// id (تحديث)</span><span class="pln">
  </span><span class="com">// خاصية =&gt; سمة </span><span class="pln">
  input</span><span class="pun">.</span><span class="pln">id </span><span class="pun">=</span><span class="pln"> </span><span class="str">'newId'</span><span class="pun">;</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln">input</span><span class="pun">.</span><span class="pln">getAttribute</span><span class="pun">(</span><span class="str">'id'</span><span class="pun">));</span><span class="pln"> </span><span class="com">// newId (تحديث)</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-06-Attributes and properties-ex8" src="https://codepen.io/Hsoub/embed/preview/poNzxXO?height=265&amp;theme-id=light&amp;default-tab=html,result">See the Pen JS-p2-06-Attributes and properties-ex8 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	غير أن هناك بعض الاستثناءات، فعلى سبيل المثال، لا يمكن مزامنة <code>input.value</code> سوى في اتجاه واحد، من السمة إلى الخاصية، وليس العكس.
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_3921_23" style="">
<span class="tag">&lt;input&gt;</span><span class="pln">
</span><span class="tag">&lt;script&gt;</span><span class="pln">
  let input </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">'input'</span><span class="pun">);</span><span class="pln">
  </span><span class="com">// سمة ⇐ خاصية</span><span class="pln">
  input</span><span class="pun">.</span><span class="pln">setAttribute</span><span class="pun">(</span><span class="str">'value'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'text'</span><span class="pun">);</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln">input</span><span class="pun">.</span><span class="pln">value</span><span class="pun">);</span><span class="pln"> </span><span class="com">// text</span><span class="pln">
  </span><span class="com">//خاصية ⇍ سمة</span><span class="pln">
  input</span><span class="pun">.</span><span class="pln">value </span><span class="pun">=</span><span class="pln"> </span><span class="str">'newValue'</span><span class="pun">;</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln">input</span><span class="pun">.</span><span class="pln">getAttribute</span><span class="pun">(</span><span class="str">'value'</span><span class="pun">));</span><span class="pln"> </span><span class="com">// text (لم يتم التحديث)</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-06-Attributes and properties-ex9" src="https://codepen.io/Hsoub/embed/preview/GRNKYVW?height=265&amp;theme-id=light&amp;default-tab=html,result">See the Pen JS-p2-06-Attributes and properties-ex9 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	في المثال أعلاه:
</p>

<ul>
<li>
		يُؤدّي تعديل قيمة السمة <code>value</code> إلى تعديل الخاصية آليًا.
	</li>
	<li>
		ولكن التعديل على الخاصية مباشرةً لا يُؤدّي إلى أيّ أثر على السمة.
	</li>
</ul>
<p>
	هذه "الميزة" يمكن أن تكون فعلا مفيدة، حيث يمكن للمستخدم أن يغيّر القيمة <code>value</code>، وبعدها، إذا أردت استعادة القيمة الأولية من HTML، تجدها في السمة.
</p>

<h2>
	خاصيات DOM لها أنواع
</h2>

<p>
	لا تكون خاصيات DOM دائمًا عبارة عن سلاسل نصّية (أي من النوع <code>"string"</code>)، فمثلا خاصية <code>input.checked</code> (في مربعات الاختيار (checkbox)) تكون عبارة عن قيمة بوليانية/منطقية.
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_3921_25" style="">
<span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"input"</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"checkbox"</span><span class="pln"> </span><span class="atn">checked</span><span class="tag">&gt;</span><span class="pln"> checkbox
</span><span class="tag">&lt;script&gt;</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln">input</span><span class="pun">.</span><span class="pln">getAttribute</span><span class="pun">(</span><span class="str">'checked'</span><span class="pun">));</span><span class="pln"> </span><span class="com">// قيمة السمة من نوع سلسلة نصّية فارغة</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln">input</span><span class="pun">.</span><span class="pln">checked</span><span class="pun">);</span><span class="pln"> </span><span class="com">// قيمة الخاصية هي “true”</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-06-Attributes and properties-ex10" src="https://codepen.io/Hsoub/embed/preview/eYBOQNo?height=265&amp;theme-id=light&amp;default-tab=html,result">See the Pen JS-p2-06-Attributes and properties-ex10 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	وهناك أمثلة أخرى؛ تكون السمة <code>style</code> عبارة عن سلسلة نصّية ولكن الخاصية <code>style</code> هي كائن.
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_3921_27" style="">
<span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"div"</span><span class="pln"> </span><span class="atn">style</span><span class="pun">=</span><span class="atv">"</span><span class="pln">color</span><span class="pun">:</span><span class="pln">red</span><span class="pun">;</span><span class="pln">font</span><span class="pun">-</span><span class="pln">size</span><span class="pun">:</span><span class="lit">120</span><span class="pun">%</span><span class="atv">"</span><span class="tag">&gt;</span><span class="pln">Hello</span><span class="tag">&lt;/div&gt;</span><span class="pln">
</span><span class="tag">&lt;script&gt;</span><span class="pln">
  </span><span class="com">// سلسلة نصّية</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln">div</span><span class="pun">.</span><span class="pln">getAttribute</span><span class="pun">(</span><span class="str">'style'</span><span class="pun">));</span><span class="pln"> </span><span class="com">// color:red;font-size:120%</span><span class="pln">
  </span><span class="com">// كائن </span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln">div</span><span class="pun">.</span><span class="pln">style</span><span class="pun">);</span><span class="pln"> </span><span class="com">// [object CSSStyleDeclaration]</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln">div</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">color</span><span class="pun">);</span><span class="pln"> </span><span class="com">// red</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-06-Attributes and properties-ex11" src="https://codepen.io/Hsoub/embed/preview/gOLYQPx?height=265&amp;theme-id=light&amp;default-tab=html,result">See the Pen JS-p2-06-Attributes and properties-ex11 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	غير أن غالبية الخاصيات تكون من نوع سلاسل نصّية.
</p>

<p>
	وفي حالات نادرة جدًا، حتى وإن كانت خاصية DOM من نوع سلسلة نصّية، يمكن أن تختلف عن السمة. فمثلا، خاصية <code>href</code> في DOM تكون دائما عبارة عن عنوان URL مطلق كامل، حتى وإن تضمّنت السمة عنوان URL نسبي أو إشارةً إلى أحد العناصر في الصفحة عبر الصياغة <code>hash#</code>. وفيما يلي مثالٌ على ذلك.
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_3921_29" style="">
<span class="tag">&lt;a</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"a"</span><span class="pln"> </span><span class="atn">href</span><span class="pun">=</span><span class="atv">"#hello"</span><span class="tag">&gt;</span><span class="pln">link</span><span class="tag">&lt;/a&gt;</span><span class="pln">
</span><span class="tag">&lt;script&gt;</span><span class="pln">
  </span><span class="com">// attribute</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln">a</span><span class="pun">.</span><span class="pln">getAttribute</span><span class="pun">(</span><span class="str">'href'</span><span class="pun">));</span><span class="pln"> </span><span class="com">// #hello</span><span class="pln">

  </span><span class="com">// property</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln">a</span><span class="pun">.</span><span class="pln">href </span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫ URL  كامل على شكل http://site.com/page#hello </span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-06-Attributes and properties-ex12" src="https://codepen.io/Hsoub/embed/preview/qBqWQZb?height=265&amp;theme-id=light&amp;default-tab=html,result">See the Pen JS-p2-06-Attributes and properties-ex12 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	إذا ما أردت الوصول إلى قيمة <code>href</code>، أو أيّ سمةٍ غيرها، كما هي مدّونة بالضبط في شيفرة HTML، استعمل الخاصية <code>getAttribute</code>.
</p>

<h2>
	السمات غير المعيارية والخاصية dataset
</h2>

<p>
	نستخدم الكثير من السمات المعيارية عند الكتابة بلغة جافاسكربت ولكن ماذا عن السمات غير المعيارية وهل هي مفيدة؟ فلنرى أولا إن كانت مفيدة أم لا وما هو دورها.
</p>

<p>
	تُستخدم أحيانا السمات غير المعيارية في تمرير البيانات من شيفرة HTML إلى جافاسكربت أو لـ : "وسم" عناصر HTML حتى تتعرّف عليها جافاسكربت.
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_3921_31" style="">
<span class="com">&lt;!-- وسم العنصر div لإظهار الاسم هنا--&gt;</span><span class="pln">
</span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">show-info</span><span class="pun">=</span><span class="atv">"name"</span><span class="tag">&gt;&lt;/div&gt;</span><span class="pln">
</span><span class="com">&lt;!-- والعمر هنا --&gt;</span><span class="pln">
</span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">show-info</span><span class="pun">=</span><span class="atv">"age"</span><span class="tag">&gt;&lt;/div&gt;</span><span class="pln">
</span><span class="tag">&lt;script&gt;</span><span class="pln">
  </span><span class="com">// تجد الشيفرة العنصر الموسوم وتقوم بإظهار المطلوب</span><span class="pln">
  let user </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Pete"</span><span class="pun">,</span><span class="pln">
    age</span><span class="pun">:</span><span class="pln"> </span><span class="lit">25</span><span class="pln">
  </span><span class="pun">};</span><span class="pln">
  </span><span class="kwd">for</span><span class="pun">(</span><span class="pln">let div of document</span><span class="pun">.</span><span class="pln">querySelectorAll</span><span class="pun">(</span><span class="str">'[show-info]'</span><span class="pun">))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// ملئ الحقل بالمعلومات الموافقة له</span><span class="pln">
    let field </span><span class="pun">=</span><span class="pln"> div</span><span class="pun">.</span><span class="pln">getAttribute</span><span class="pun">(</span><span class="str">'show-info'</span><span class="pun">);</span><span class="pln">
    div</span><span class="pun">.</span><span class="pln">innerHTML </span><span class="pun">=</span><span class="pln"> user</span><span class="pun">[</span><span class="pln">field</span><span class="pun">];</span><span class="pln"> </span><span class="com">//(*) </span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-06-Attributes and properties-ex13" src="https://codepen.io/Hsoub/embed/preview/GRNKwZv?height=265&amp;theme-id=light&amp;default-tab=html,result">See the Pen JS-p2-06-Attributes and properties-ex13 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	(*): إظهارالقيمة "Pete" داخل العنصر <code>div</code> الموسوم بـ <code>name</code> وإظهار القيمة <code>25</code> داخل العنصر <code>div</code> الموسوم بـ<code>age</code>. كما يمكن استعمالها لتنسيق عنصر ما. فمثلا، تُستخدم هنا السمة <code>order-state</code> للتعبير عن حالة الطلب (إن كان جديدًا، معلّقًا أو ملغى).
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_3921_33" style="">
<span class="tag">&lt;style&gt;</span><span class="pln">
  </span><span class="com">/* تعتمد الأنماط على السمة غير المعيارية 'order-state' */</span><span class="pln">
  </span><span class="pun">.</span><span class="pln">order</span><span class="pun">[</span><span class="pln">order</span><span class="pun">-</span><span class="pln">state</span><span class="pun">=</span><span class="str">"new"</span><span class="pun">]</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    color</span><span class="pun">:</span><span class="pln"> green</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">.</span><span class="pln">order</span><span class="pun">[</span><span class="pln">order</span><span class="pun">-</span><span class="pln">state</span><span class="pun">=</span><span class="str">"pending"</span><span class="pun">]</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    color</span><span class="pun">:</span><span class="pln"> blue</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">.</span><span class="pln">order</span><span class="pun">[</span><span class="pln">order</span><span class="pun">-</span><span class="pln">state</span><span class="pun">=</span><span class="str">"canceled"</span><span class="pun">]</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    color</span><span class="pun">:</span><span class="pln"> red</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="tag">&lt;/style&gt;</span><span class="pln">
</span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"order"</span><span class="pln"> </span><span class="atn">order-state</span><span class="pun">=</span><span class="atv">"new"</span><span class="tag">&gt;</span><span class="pln">
  A new order.
</span><span class="tag">&lt;/div&gt;</span><span class="pln">
</span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"order"</span><span class="pln"> </span><span class="atn">order-state</span><span class="pun">=</span><span class="atv">"pending"</span><span class="tag">&gt;</span><span class="pln">
  A pending order.
</span><span class="tag">&lt;/div&gt;</span><span class="pln">
</span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"order"</span><span class="pln"> </span><span class="atn">order-state</span><span class="pun">=</span><span class="atv">"canceled"</span><span class="tag">&gt;</span><span class="pln">
  A canceled order.
</span><span class="tag">&lt;/div&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-06-Attributes and properties-ex14" src="https://codepen.io/Hsoub/embed/preview/VwmZVjm?height=265&amp;theme-id=light&amp;default-tab=html,result">See the Pen JS-p2-06-Attributes and properties-ex14 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	لماذا يُستحسن استخدام السمة بدل استخدام الأصناف <code>order-state-canceled.</code> و<code>order-state-pending.</code> و <code>order-state-new.</code>؟ ذلك لأنه يَسهُل استعمال الخاصيات موازنةً مع الأصناف حيث يمكن تعديل الحالة بمنتهى السهولة كما في المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3921_35" style="">
<span class="com">// أسهل من حذف/إضافة صنف جديد</span><span class="pln">
div</span><span class="pun">.</span><span class="pln">setAttribute</span><span class="pun">(</span><span class="str">'order-state'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'canceled'</span><span class="pun">);</span></pre>

<p>
	ولكن السمات غير المعيارية قد تتسبّب في المشكل التالي: ماذا لو استُخدمت سمةٌ غير معياريةٍ لغرضٍ ما وبعدها اِستُحدِثت كسمةٍ معياريةٍ تقوم بوظيفةٍ ما؟ تُعد لغة HTML حيّةً، ومتطورةً، حيث تَستحدِث باستمرار سماتٍ جديدةٍ تلبّي حاجات المطوّرين. قد ينجرّ عن هذا الأمر انعكاساتٍ غير متوقعة. ولتفادي حصول مثل هذا التضارب وُجدت السمات <code>*-data</code>.
</p>

<p>
	كلّ السمات التي تبدأ بـ <a href="https://html.spec.whatwg.org/#embedding-custom-non-visible-data-with-the-data-*-attributes" rel="external nofollow">"-data"</a> هي سمات محجوزة يستعملها المطوّرون فقط. ويمكن الوصول إليها عبر الخاصية <code>dataset</code>. فمثلا، إذا كانت السمة المسمّاة <code>"data-about"</code> تابعة للعنصر <code>elem</code> ، يمكن الوصول إليها باستعمال <code>elem.dataset.about</code> كالآتي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_3921_37" style="">
<span class="tag">&lt;body</span><span class="pln"> </span><span class="atn">data-about</span><span class="pun">=</span><span class="atv">"Elephants"</span><span class="tag">&gt;</span><span class="pln">
</span><span class="tag">&lt;script&gt;</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln">document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">dataset</span><span class="pun">.</span><span class="pln">about</span><span class="pun">);</span><span class="pln"> </span><span class="com">// Elephants</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-06-Attributes and properties-ex15" src="https://codepen.io/Hsoub/embed/preview/ZEBzmOZ?height=265&amp;theme-id=light&amp;default-tab=html,result">See the Pen JS-p2-06-Attributes and properties-ex15 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	تُصبح أسماء السمات التي تتكوّن من عدّة كلمات مثل <code>data-order-state</code> على الشكل: <code>dataset.orderState</code>، حيث تُكتب -عند استعمالها كخاصيات- بنمط سنام الجمل أي بجعل أول حرف من كلّ كلمة كبيرًا عدا الكلمة الأولى. نعيد فيما يلي كتابة المثال السابق (المثال الخاص بـ "حالة الطلب") بطريقة أخرى.
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_3921_39" style="">
<span class="tag">&lt;style&gt;</span><span class="pln">
  </span><span class="pun">.</span><span class="pln">order</span><span class="pun">[</span><span class="pln">data</span><span class="pun">-</span><span class="pln">order</span><span class="pun">-</span><span class="pln">state</span><span class="pun">=</span><span class="str">"new"</span><span class="pun">]</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    color</span><span class="pun">:</span><span class="pln"> green</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">.</span><span class="pln">order</span><span class="pun">[</span><span class="pln">data</span><span class="pun">-</span><span class="pln">order</span><span class="pun">-</span><span class="pln">state</span><span class="pun">=</span><span class="str">"pending"</span><span class="pun">]</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    color</span><span class="pun">:</span><span class="pln"> blue</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">.</span><span class="pln">order</span><span class="pun">[</span><span class="pln">data</span><span class="pun">-</span><span class="pln">order</span><span class="pun">-</span><span class="pln">state</span><span class="pun">=</span><span class="str">"canceled"</span><span class="pun">]</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    color</span><span class="pun">:</span><span class="pln"> red</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="tag">&lt;/style&gt;</span><span class="pln">
</span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"order"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"order"</span><span class="pln"> </span><span class="atn">data-order-state</span><span class="pun">=</span><span class="atv">"new"</span><span class="tag">&gt;</span><span class="pln">
  A new order.
</span><span class="tag">&lt;/div&gt;</span><span class="pln">
</span><span class="tag">&lt;script&gt;</span><span class="pln">
  </span><span class="com">// قراءة </span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln">order</span><span class="pun">.</span><span class="pln">dataset</span><span class="pun">.</span><span class="pln">orderState</span><span class="pun">);</span><span class="pln"> </span><span class="com">// new</span><span class="pln">
  </span><span class="com">// تعديل </span><span class="pln">
  order</span><span class="pun">.</span><span class="pln">dataset</span><span class="pun">.</span><span class="pln">orderState </span><span class="pun">=</span><span class="pln"> </span><span class="str">"pending"</span><span class="pun">;</span><span class="pln"> </span><span class="com">// (*)</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-06-Attributes and properties-ex16" src="https://codepen.io/Hsoub/embed/preview/NWbKERz?height=265&amp;theme-id=light&amp;default-tab=html,result">See the Pen JS-p2-06-Attributes and properties-ex16 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	يُعدّ استعمال السمات التي تبدأ بـ <code>*-data</code> طريقةً فعالةً وآمنةً لتمرير البيانات غير المعيارية. لاحظ هنا أنه لا يمكنك قراءة السمات <code>*-data</code> فحسب، بل حتى تعديلها، ومن ثمّ تُطبَّق تنسيقات CSS بناءً عليها. في المثال أعلاه، غيّرت تعليمة السطر الأخير (الموسوم بالرمز <code>(*)</code>) اللّون ليصبح أزرقًا.
</p>

<h2>
	الخلاصة
</h2>

<ul>
<li>
		السمة هي ما يدوّن على شيفرة HTML
	</li>
	<li>
		الخاصية هي ما يندرج ضمن الكائن DOM
	</li>
</ul>
<p>
	<strong>موازنة بسيطة</strong>
</p>

<table>
<thead><tr>
<th>
				 
			</th>
			<th>
				الخاصيات
			</th>
			<th>
				السمات
			</th>
		</tr></thead>
<tbody>
<tr>
<td>
				<strong>النوع</strong>
			</td>
			<td>
				أيّ قيمةٍ كانت، للخاصيات أنواعٌ موضّحةٌ في المواصفة التقنية
			</td>
			<td>
				سلسلة نصّية
			</td>
		</tr>
<tr>
<td>
				<strong>الاسم</strong>
			</td>
			<td>
				يخضع لشرط التمييز بين الحروف الكبيرة والحروف الصغيرة
			</td>
			<td>
				لا يخضع لشرط التمييز بين الحروف الكبيرة والحروف الصغيرة
			</td>
		</tr>
</tbody>
</table>
<style type="text/css">
table {
    width: 100%;
}

thead {
    vertical-align: middle;

    text-align: center;} 

td, th {
    border: 1px solid #dddddd;
    text-align: right;
    padding: 8px;
    text-align: inherit;

}
tr:nth-child(even) {
    background-color: #dddddd;
}</style>
<p>
	دوالّ العمليات على السمات هي:
</p>

<ul>
<li>
		<code>(elem.hasAttribute(name</code>: للتحقق من وجود السمة.
	</li>
	<li>
		<code>(elem.getAttribute(name</code>: للحصول على قيمة السمة.
	</li>
	<li>
		<code>(elem.setAttribute(name, value</code>: إسناد القيمة <code>value</code> للسمة <code>name</code>.
	</li>
	<li>
		<code>(elem.removeAttribute(name</code>: حذف السمة.
	</li>
	<li>
		<code>elem.attributes</code>: يمثّل مجموعة السمات الخاصة بالعنصر المحدد.
	</li>
</ul>
<p>
	ويُستحسن استعمال خاصيات DOM في أغلب الحالات، وعليك اللجوء إلى استعمال السمات فقط حين تحتاج إلى ذلك وإذا كان استعمال خاصيات DOM لا يفي بالغرض. مثلا: *تحتاج إلى سمةٍ غير معيارية، ولكن إن كانت تبدأ بـ <code>-data</code> عليك استعمال<code>dataset</code>. *تُريد قراءة القيمة كما هي مكتوبة بالضبط في شيفرة HTML. قد تكون قيمة الخاصية DOM مختلفةً عنها. فمثلا، تكون الخاصية <code>href</code> دائما عبارة عن عنوان URL مطلق كامل، وقد تحتاج أنت الوصول إلى القيمة الأصلية/الأولى.
</p>

<h2>
	تمارين
</h2>

<h3>
	الوصول إلى سمةٍ ما
</h3>

<p>
	<em>درجة الأهمية: 5</em><br>
	اُكتب الشيفرة التي تسمح باختيار العنصر من المستند باستعمال السمة <code>data-widget-name</code> وقراءة قيمتها.
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_3921_41" style="">
<span class="dec">&lt;!DOCTYPE html&gt;</span><span class="pln">
</span><span class="tag">&lt;html&gt;</span><span class="pln">
</span><span class="tag">&lt;body&gt;</span><span class="pln">
  </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">data-widget-name</span><span class="pun">=</span><span class="atv">"menu"</span><span class="tag">&gt;</span><span class="pln">Choose the genre</span><span class="tag">&lt;/div&gt;</span><span class="pln">
  </span><span class="tag">&lt;script&gt;</span><span class="pln">
    </span><span class="com">/*أكتب الشيفرة هنا */</span><span class="pln">
  </span><span class="tag">&lt;/script&gt;</span><span class="pln">
</span><span class="tag">&lt;/body&gt;</span><span class="pln">
</span><span class="tag">&lt;/html&gt;</span></pre>

<p>
	<strong>الحل</strong>
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_3921_43" style="">
<span class="dec">&lt;!DOCTYPE html&gt;</span><span class="pln">
</span><span class="tag">&lt;html&gt;</span><span class="pln">
</span><span class="tag">&lt;body&gt;</span><span class="pln">
  </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">data-widget-name</span><span class="pun">=</span><span class="atv">"menu"</span><span class="tag">&gt;</span><span class="pln">Choose the genre</span><span class="tag">&lt;/div&gt;</span><span class="pln">
  </span><span class="tag">&lt;script&gt;</span><span class="pln">
    </span><span class="com">// الحصول عليه</span><span class="pln">
    let elem </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">'[data-widget-name]'</span><span class="pun">);</span><span class="pln">
    </span><span class="com">// قراءة القيمة </span><span class="pln">
    alert</span><span class="pun">(</span><span class="pln">elem</span><span class="pun">.</span><span class="pln">dataset</span><span class="pun">.</span><span class="pln">widgetName</span><span class="pun">);</span><span class="pln">
    </span><span class="com">// أو</span><span class="pln">
    alert</span><span class="pun">(</span><span class="pln">elem</span><span class="pun">.</span><span class="pln">getAttribute</span><span class="pun">(</span><span class="str">'data-widget-name'</span><span class="pun">));</span><span class="pln">
  </span><span class="tag">&lt;/script&gt;</span><span class="pln">
</span><span class="tag">&lt;/body&gt;</span><span class="pln">
</span><span class="tag">&lt;/html&gt;</span></pre>

<h3>
	تغيير لون الروابط الخارجية إلى البرتقالي
</h3>

<p>
	<em>درجة الأهمية: 3</em><br>
	غيّر لون جميع الروابط الخارجية إلى البرتقالي من خلال التعديل على خاصية <code>style</code> . يُعدّ الرابط خارجيًا إذا:
</p>

<ul>
<li>
		كانت السمة <code>href</code> الخاصة به تضمّ السلسلة النصّية '//:'
	</li>
	<li>
		لم تكن تبدأ بـالسلسلة النصّية 'http://internal.com'
	</li>
</ul>
<p>
	مثال:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_3921_45" style="">
<span class="tag">&lt;a</span><span class="pln"> </span><span class="atn">name</span><span class="pun">=</span><span class="atv">"list"</span><span class="tag">&gt;</span><span class="pln">the list</span><span class="tag">&lt;/a&gt;</span><span class="pln">
</span><span class="tag">&lt;ul&gt;</span><span class="pln">
  </span><span class="tag">&lt;li&gt;&lt;a</span><span class="pln"> </span><span class="atn">href</span><span class="pun">=</span><span class="atv">"http://google.com"</span><span class="tag">&gt;</span><span class="pln">http://google.com</span><span class="tag">&lt;/a&gt;&lt;/li&gt;</span><span class="pln">
  </span><span class="tag">&lt;li&gt;&lt;a</span><span class="pln"> </span><span class="atn">href</span><span class="pun">=</span><span class="atv">"/tutorial"</span><span class="tag">&gt;</span><span class="pln">/tutorial.html</span><span class="tag">&lt;/a&gt;&lt;/li&gt;</span><span class="pln">
  </span><span class="tag">&lt;li&gt;&lt;a</span><span class="pln"> </span><span class="atn">href</span><span class="pun">=</span><span class="atv">"local/path"</span><span class="tag">&gt;</span><span class="pln">local/path</span><span class="tag">&lt;/a&gt;&lt;/li&gt;</span><span class="pln">
  </span><span class="tag">&lt;li&gt;&lt;a</span><span class="pln"> </span><span class="atn">href</span><span class="pun">=</span><span class="atv">"ftp://ftp.com/my.zip"</span><span class="tag">&gt;</span><span class="pln">ftp://ftp.com/my.zip</span><span class="tag">&lt;/a&gt;&lt;/li&gt;</span><span class="pln">
  </span><span class="tag">&lt;li&gt;&lt;a</span><span class="pln"> </span><span class="atn">href</span><span class="pun">=</span><span class="atv">"http://nodejs.org"</span><span class="tag">&gt;</span><span class="pln">http://nodejs.org</span><span class="tag">&lt;/a&gt;&lt;/li&gt;</span><span class="pln">
  </span><span class="tag">&lt;li&gt;&lt;a</span><span class="pln"> </span><span class="atn">href</span><span class="pun">=</span><span class="atv">"http://internal.com/test"</span><span class="tag">&gt;</span><span class="pln">http://internal.com/test</span><span class="tag">&lt;/a&gt;&lt;/li&gt;</span><span class="pln">
</span><span class="tag">&lt;/ul&gt;</span><span class="pln">
</span><span class="tag">&lt;script&gt;</span><span class="pln">
  </span><span class="com">// تنسيق رابط واحد</span><span class="pln">
  let link </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">'a'</span><span class="pun">);</span><span class="pln">
  link</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">color </span><span class="pun">=</span><span class="pln"> </span><span class="str">'orange'</span><span class="pun">;</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	ينبغي أن تكون النتيجة كالآتي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="56602" href="https://academy.hsoub.com/uploads/monthly_2021_01/001orangeExternalLinks.png.09fa0947af79fe1d185da340462055bf.png" rel=""><img alt="001orangeExternalLinks.png" class="ipsImage ipsImage_thumbnailed" data-fileid="56602" data-unique="c3lg51c10" src="https://academy.hsoub.com/uploads/monthly_2021_01/001orangeExternalLinks.png.09fa0947af79fe1d185da340462055bf.png"></a>
</p>

<p>
	<strong>الحل</strong>
</p>

<p>
	عليك أولا إيجاد كلّ الروابط الخارجية. وهناك طريقتان: الأولى من خلال إيجاد كافة الروابط باستعمال <code>('document.querySelectorAll('a</code> وبعدها أخذ ما تحتاج إليه فقط.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3921_47" style="">
<span class="pln">let links </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">querySelectorAll</span><span class="pun">(</span><span class="str">'a'</span><span class="pun">);</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let link of links</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  let href </span><span class="pun">=</span><span class="pln"> link</span><span class="pun">.</span><span class="pln">getAttribute</span><span class="pun">(</span><span class="str">'href'</span><span class="pun">);</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(!</span><span class="pln">href</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">continue</span><span class="pun">;</span><span class="pln"> </span><span class="com">// لا وجود للسمة </span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(!</span><span class="pln">href</span><span class="pun">.</span><span class="pln">includes</span><span class="pun">(</span><span class="str">'://'</span><span class="pun">))</span><span class="pln"> </span><span class="kwd">continue</span><span class="pun">;</span><span class="pln"> </span><span class="com">// لا وجود للسلسلة النصية '://' </span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">href</span><span class="pun">.</span><span class="pln">startsWith</span><span class="pun">(</span><span class="str">'http://internal.com'</span><span class="pun">))</span><span class="pln"> </span><span class="kwd">continue</span><span class="pun">;</span><span class="pln"> </span><span class="com">// رابط داخلي </span><span class="pln">
  link</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">color </span><span class="pun">=</span><span class="pln"> </span><span class="str">'orange'</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لاحظ هنا أنّنا نستعمل <code>('link.getAttribute('href</code> وليس <code>link.href</code> لأنّنا نريد استخراج القيمة من شيفرة HTML . والطريقة الثانية، أبسط من الأولى، تكون بإضافة عمليات التحقّق لمحدّد CSS:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3921_49" style="">
<span class="pln"> </span><span class="pun">البحث</span><span class="pln"> </span><span class="pun">في</span><span class="pln"> href </span><span class="pun">عن</span><span class="pln"> </span><span class="pun">كلّ</span><span class="pln"> </span><span class="pun">الروابط</span><span class="pln"> </span><span class="pun">التي</span><span class="pln"> </span><span class="pun">تضمّ</span><span class="pln"> </span><span class="pun">السلسلة</span><span class="pln"> </span><span class="pun">النصّية</span><span class="pln"> </span><span class="str">'//:'</span><span class="pln"> </span><span class="com">//  </span><span class="pln">
</span><span class="com">//  ولا تبدأ بـالسلسلة النصّية 'http://internal.com'</span><span class="pln">
let selector </span><span class="pun">=</span><span class="pln"> </span><span class="str">'a[href*="://"]:not([href^="http://internal.com"])'</span><span class="pun">;</span><span class="pln">
let links </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">querySelectorAll</span><span class="pun">(</span><span class="pln">selector</span><span class="pun">);</span><span class="pln">
links</span><span class="pun">.</span><span class="pln">forEach</span><span class="pun">(</span><span class="pln">link </span><span class="pun">=&gt;</span><span class="pln"> link</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">color </span><span class="pun">=</span><span class="pln"> </span><span class="str">'orange'</span><span class="pun">);</span></pre>

<p>
	ترجمة -وبتصرف- للفصل <a href="https://javascript.info/dom-attributes-and-properties#dom-properties" rel="external nofollow">Attributes and properties</a> من كتاب <a href="https://javascript.info/ui" rel="external nofollow">Browser: Document, Events, Interfaces</a>
</p>
]]></description><guid isPermaLink="false">1116</guid><pubDate>Wed, 27 Jan 2021 13:00:00 +0000</pubDate></item><item><title>&#x627;&#x633;&#x62A;&#x643;&#x634;&#x627;&#x641; &#x62E;&#x627;&#x635;&#x64A;&#x627;&#x62A; &#x639;&#x642;&#x62F; DOM &#x628;&#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A;: &#x627;&#x644;&#x635;&#x646;&#x641; &#x648;&#x627;&#x644;&#x648;&#x633;&#x645; &#x648;&#x627;&#x644;&#x645;&#x62D;&#x62A;&#x648;&#x64A;&#x627;&#x62A;</title><link>https://academy.hsoub.com/programming/javascript/%D8%A7%D8%B3%D8%AA%D9%83%D8%B4%D8%A7%D9%81-%D8%AE%D8%A7%D8%B5%D9%8A%D8%A7%D8%AA-%D8%B9%D9%82%D8%AF-dom-%D8%A8%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-%D8%A7%D9%84%D8%B5%D9%86%D9%81-%D9%88%D8%A7%D9%84%D9%88%D8%B3%D9%85-%D9%88%D8%A7%D9%84%D9%85%D8%AD%D8%AA%D9%88%D9%8A%D8%A7%D8%AA-r1107/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_01/600fec8d56724_--DOM.png.cdfe585a994533bab24d8fae170a3317.png" /></p>

<p>
	لنتناول عُقدَ DOM بمزيدٍ من التعمّق. في هذا المقال، سننظر أكثر في ماهيّتها وسنتعرّف على أكثر خاصّيّاتها استخداما.
</p>

<h2>
	أصناف العقد في DOM
</h2>

<p>
	قد تختلف خاصّيات العقد باختلاف العقد نفسها. فعلى سبيل المثال، تملك العقد التي تمثّل الوسم <code>&lt;a&gt;</code> خاصّيّات تتعلّق بالروابط، وتملك العقد التي تمثّل الوسم <code>&lt;input&gt;</code> خاصّيّات تتعلّق بالمُدخلات، وهكذا. لكن بالرغم من اختلاف العقد عن بعضها، فإنّ لها أيضا خاصّيّات وتوابع مشتركة بينها، ﻷنّ جميع أصناف العقد في DOM تُشكّل تسلسلا هرميّا واحدا.
</p>

<p>
	تنتمي كلّ عقدة من DOM إلى صنف معيّن من اﻷصناف المسبقة البناء (built-in class).
</p>

<p>
	يكون جذر التسلسل الهرميّ هو الصنف <a href="https://dom.spec.whatwg.org/#eventtarget" rel="external nofollow">EventTarget</a>، الذي يرث عنه الصنفُ <a href="http://dom.spec.whatwg.org/#interface-node" rel="external nofollow">Node</a>، الذي يرث عنه بدوره باقي العقد في DOM.
</p>

<p>
	هذه صورة للتسلسل الهرمي، وسيتبعها المزيد من الشرح:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="56443" href="https://academy.hsoub.com/uploads/monthly_2021_01/dom-class-hierarchy.png.280c20fa26aa10bb978bb50c6df64d07.png" rel=""><img alt="dom-class-hierarchy.png" class="ipsImage ipsImage_thumbnailed" data-fileid="56443" data-unique="6za0ewpl4" src="https://academy.hsoub.com/uploads/monthly_2021_01/dom-class-hierarchy.png.280c20fa26aa10bb978bb50c6df64d07.png"></a>
</p>

<p>
	تتمثّل اﻷصناف في:
</p>

<ul>
<li>
		<a href="https://dom.spec.whatwg.org/#eventtarget" rel="external nofollow">EventTarget</a> -- هو صنفٌ "مجرّدٌ" (abstract) يكون عند الجذر. لا تُنشأ كائنات من هذا الصنف أبدا. وهو بمثابة القاعدة التي تُمكّن جميع العُقد في DOM من دعم من يُسمّى باﻷحداث (التي سندرسها لاحقا).
	</li>
	<li>
		<a href="http://dom.spec.whatwg.org/#interface-node" rel="external nofollow">Node</a> -- هو أيضا صنفٌ "مجرّد" بمثابة القاعدة للعقد في DOM، ويوفّر الوظائف الشجريّة اﻷساسيّة مثل <code>parentNode</code> و <code>nextSibling</code> و <code>childNodes</code> وغيرها (التي تُسمّى جالبة - getters). لا تُنشأ كائنات من هذا الصنف، لكنّ هناك أصنافا حقيقيّة (concrete) من العُقد التي ترث هذا الصنف، منها <code>Text</code> للعقد النصّيّة و <code>Element</code> للعقد العنصريّة وأصنافٌ أخرى أغرب مثل <code>Comment</code> للعقد التعليقيّة.
	</li>
	<li>
		<a href="http://dom.spec.whatwg.org/#interface-element" rel="external nofollow">Element</a> -- هو الصنف الأساسيّ للعناصر في DOM. يتيح توابع للتنقّل بين العناصر مثل <code>nextElementSibling</code> و <code>children</code> وتوابع للبحث مثل <code>getElementsByTagName</code> و <code>querySelector</code>. بما أنّ المتصفّح لا يدعم فقط HTML بل XML و SVG كذلك، فإنّ الصنف <code>Element</code> يمثّل قاعدة لأصنافٍ أخصّ مثل <code>SVGElement</code> و <code>XMLElement</code> و <code>HTMLElement</code>.
	</li>
	<li>
		<a href="https://html.spec.whatwg.org/multipage/dom.html#htmlelement" rel="external nofollow">HTMLElement</a> -- هو الصنف اﻷساسيّ لجميع عناصر HTML ، ويرث عنه عناصرُ HTML الحقيقيّة:
	</li>
	<li>
		<a href="https://html.spec.whatwg.org/multipage/forms.html#htmlinputelement" rel="external nofollow">HTMLInputElement</a> -- هو صنف العناصر <code>&lt;input&gt;</code>.
	</li>
	<li>
		<a href="https://html.spec.whatwg.org/multipage/semantics.html#htmlbodyelement" rel="external nofollow">HTMLBodyElement</a> -- هو صنف العناصر <code>&lt;body&gt;</code>.
	</li>
	<li>
		<a href="https://html.spec.whatwg.org/multipage/semantics.html#htmlanchorelement" rel="external nofollow">HTMLAnchorElement</a> -- هو صنف العناصر <code>&lt;a&gt;</code>.
	</li>
	<li>
		… إلى غير ذلك، فلكلّ وسمٍ صنفه الخاصّ الذي قد يتيح له خاصّيّات وتوابع تختصّ به.
	</li>
</ul>
<p>
	إذًا فمجموع الخاصّيّات والتوابع التي لدى عقدةٍ ما هو ناتج عن الوراثة.
</p>

<p>
	على سبيل المثال، لنأخذ كائن DOM لعنصر <code>&lt;input&gt;</code>. ينتمي هذا الكائن إلى صنف <a href="https://html.spec.whatwg.org/multipage/forms.html#htmlinputelement" rel="external nofollow">HTMLInputElement</a>، ويكتسب خاصّياته وتوابعه من تراكم اﻷصناف التالية (مرتبة بحسب الوراثة):
</p>

<ul>
<li>
		<code>HTMLInputElement</code> -- يتيح هذا الصنف خاصّيّات تتعلّق بالمُدخلات.
	</li>
	<li>
		<code>HTMLElement</code> -- يتيح توابع مشتركة بين عناصر HTML (وجوالب/ضوابط -- getters/setters).
	</li>
	<li>
		<code>Element</code> -- يتيح توابع عامّة للعناصر.
	</li>
	<li>
		<code>Node</code> -- يتيح خاصّيات مشتركة بين عقد DOM.
	</li>
	<li>
		<code>EventTarget</code> -- يتيح الدعم للأحداث (سنتطرق لها لاحقا).
	</li>
	<li>
		… وأخيرا هو يرث من <code>Object</code> ، مما يجعل توابع "الكائنات الصرفة" مثل <code>hasOwnProperty</code> متاحة له كذلك.
	</li>
</ul>
<p>
	لمعرفة اسم صنف العقدة في DOM، يكفي تذكّر أنّ للكائنات عادةً خاصّيّة <code>constructor</code>. تشير هذه الخاصّيّة إلى الدالّة البانية (constructor) الخاصّة بالصنف، و <code>constructor.name</code> هو اسمها:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3421_7" style="">
<span class="pln">alert</span><span class="pun">(</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">constructor</span><span class="pun">.</span><span class="pln">name </span><span class="pun">);</span><span class="pln"> </span><span class="com">// HTMLBodyElement</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="186" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-05-basic-dom-node-properties-ex1" src="https://codepen.io/Hsoub/embed/preview/KKgOVMN?height=186&amp;theme-id=light&amp;default-tab=js,result">See the Pen JS-p2-05-basic-dom-node-properties-ex1 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	… أو يكفي مجرّد تطبيق <code>toString</code> عليه:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3421_9" style="">
<span class="pln">alert</span><span class="pun">(</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">body </span><span class="pun">);</span><span class="pln"> </span><span class="com">// [object HTMLBodyElement]</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="183" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-05-basic-dom-node-properties-ex2" src="https://codepen.io/Hsoub/embed/preview/zYKgrBp?height=183&amp;theme-id=light&amp;default-tab=js,result">See the Pen JS-p2-05-basic-dom-node-properties-ex2 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	يمكن كذلك استخدام <code>instanceof</code> للتحقّق من الوراثة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3421_11" style="">
<span class="pln">alert</span><span class="pun">(</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">body instanceof </span><span class="typ">HTMLBodyElement</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// true</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">body instanceof </span><span class="typ">HTMLElement</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// true</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">body instanceof </span><span class="typ">Element</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// true</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">body instanceof </span><span class="typ">Node</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// true</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">body instanceof </span><span class="typ">EventTarget</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// true</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-05-basic-dom-node-properties-ex3" src="https://codepen.io/Hsoub/embed/preview/gOwVPMV?height=265&amp;theme-id=light&amp;default-tab=js,result">See the Pen JS-p2-05-basic-dom-node-properties-ex3 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	كما يمكن أن نلاحظ، تُعدّ عقد DOM كائنات جافاسكربت عاديّة، وهي تعتمد في التوريث على كائن <code>prototype</code>.
</p>

<p>
	يمكن أيضا ملاحظة ذلك بسهولة من خلال عرض عنصرٍ ما بواسطة <code>(console.dir(elem</code> في المتصفّح. يمكنك ملاحظة كلٍّ من <code>HTMLElement.prototype</code> و <code>Element.prototype</code> وغيرها في الطرفية.
</p>

<hr>
<p>
	<strong><code>(console.dir(elem</code> مقابل <code>(console.log(elem</code></strong>
</p>

<p>
	تدعم أدوات المطوّر في معظم المتصفحات اﻷمرين: <code>console.log</code> و <code>console.dir</code>. يعرض كلّ منهما معاملاته في الطرفيّة. بالنسبة لكائنات جافاسكربت فإنّ هذين اﻷمرين متماثلان في العادة.
</p>

<p>
	لكن بالنسبة لعناصر DOM فهما مختلفان:
</p>

<ul>
<li>
		تعرض <code>(console.log(elem</code> شجرة DOM الخاصّة بالعنصر.
	</li>
	<li>
		تعرض <code>(console.dir(elem</code> العنصر على شكل كائن DOM، وتساعد على استكشاف خاصيّاته.
	</li>
</ul>
<p>
	جرّب ذلك على <code>document.body</code>
</p>

<hr>
<hr>
<p>
	<strong>IDL في المواصفة</strong>
</p>

<p>
	لا توصف أصناف DOM في المواصفة باستخدام جافاسكربت، لكن باستخدام لغة خاصة تُسمى <a href="https://en.wikipedia.org/wiki/Interface_description_language" rel="external nofollow">لغة وصف الواجهة</a> (Interface description language أو IDL باختصار)، وهي سهلة الفهم في العادة.
</p>

<p>
	في IDL، تُسبق جميع الخاصّيّات بنوعها. فمثلا <code>DOMString</code> و <code>boolean</code> وهكذا.
</p>

<p>
	إليك مقتطفا منها مع التعليقات:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3421_13" style="">
<span class="com">// HTMLInputElement تعريف</span><span class="pln">
</span><span class="com">// HTMLElement يرث من HTMLInputElement تعني النقطان الرئسيتان ":" أنّ   </span><span class="pln">
interface </span><span class="typ">HTMLInputElement</span><span class="pun">:</span><span class="pln"> </span><span class="typ">HTMLElement</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">//  &lt;input&gt; هنا توضع خاصّيّات وتوابع العنصر</span><span class="pln">

  </span><span class="com">// أنّ قيمة الخاصّيّة هي عبارة عن سلسلة نصيّة "DOMString" تعني</span><span class="pln">
  attribute </span><span class="typ">DOMString</span><span class="pln"> accept</span><span class="pun">;</span><span class="pln">
  attribute </span><span class="typ">DOMString</span><span class="pln"> alt</span><span class="pun">;</span><span class="pln">
  attribute </span><span class="typ">DOMString</span><span class="pln"> autocomplete</span><span class="pun">;</span><span class="pln">
  attribute </span><span class="typ">DOMString</span><span class="pln"> value</span><span class="pun">;</span><span class="pln">

  </span><span class="com">// (true/false) خاصّيّة ذات قيمةٍ بوليانية</span><span class="pln">
  attribute boolean autofocus</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">...</span><span class="pln">
  </span><span class="com">// أن التابع لايعيد أيّة قيمة "void" وهنا مكان التابع: تعني</span><span class="pln">
  </span><span class="kwd">void</span><span class="pln"> select</span><span class="pun">();</span><span class="pln">
  </span><span class="pun">...</span><span class="pln">
</span><span class="pun">}</span></pre>

<hr>
<h2>
	خاصية "nodeType"
</h2>

<p>
	تقدّم خاصّيّة "nodeType" طريقة أخرى "قديمة الطراز" للحصول على "نوع" العقدة في DOM.
</p>

<p>
	لهذه الخاصّيّة قيمة عددية:
</p>

<ul>
<li>
		<code>elem.nodeType == 1</code> للعقد العنصريّة.
	</li>
	<li>
		<code>elem.nodeType == 3</code> للعقد النصّيّة.
	</li>
	<li>
		<code>elem.nodeType == 9</code> لكائن <code>document</code>.
	</li>
	<li>
		هناك بعض القيم اﻷخرى في <a href="https://dom.spec.whatwg.org/#node" rel="external nofollow">المواصفة</a>.
	</li>
</ul>
<p>
	على سبيل المثال:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_3421_15" style="">
<span class="tag">&lt;body&gt;</span><span class="pln">
  </span><span class="tag">&lt;script&gt;</span><span class="pln">
  let elem </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">;</span><span class="pln">

  </span><span class="com">// لنرى ما نوع هذه العقدة</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln">elem</span><span class="pun">.</span><span class="pln">nodeType</span><span class="pun">);</span><span class="pln"> </span><span class="com">// 1 =&gt; عنصر</span><span class="pln">

  </span><span class="com">// ... وأوّل ابن لها هو</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln">elem</span><span class="pun">.</span><span class="pln">firstChild</span><span class="pun">.</span><span class="pln">nodeType</span><span class="pun">);</span><span class="pln"> </span><span class="com">// 3 =&gt; نصّ</span><span class="pln">

  </span><span class="com">//  9 النوع هو ،document بالنسبة لكائن</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">nodeType </span><span class="pun">);</span><span class="pln"> </span><span class="com">// 9</span><span class="pln">
  </span><span class="tag">&lt;/script&gt;</span><span class="pln">
</span><span class="tag">&lt;/body&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-05-basic-dom-node-properties-ex4" src="https://codepen.io/Hsoub/embed/preview/jOMgWMM?height=265&amp;theme-id=light&amp;default-tab=html,result">See the Pen JS-p2-05-basic-dom-node-properties-ex4 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	في السكربتات الحديثة، يمكننا استخدام <code>instanceof</code> وغيرها من الاختبارات المعتمدة على الصنف لمعرفة نوع العقدة، لكن أحيانا قد تكون <code>nodeType</code> أبسط. يمكننا فقط قراءة <code>nodeType</code> دون التعديل عليها.
</p>

<h2>
	الوسم: nodeName و tagName
</h2>

<p>
	إذا كانت لدينا عقدة من DOM، فيمكننا قراءة اسم وسمها من خلال خاصّيّات <code>nodeName</code> و <code>tagName</code>.
</p>

<p>
	على سبيل المثال:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3421_17" style="">
<span class="pln">alert</span><span class="pun">(</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">nodeName </span><span class="pun">);</span><span class="pln"> </span><span class="com">// BODY</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">tagName </span><span class="pun">);</span><span class="pln"> </span><span class="com">// BODY</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="188" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-05-basic-dom-node-properties-ex5" src="https://codepen.io/Hsoub/embed/preview/eYdqJBG?height=188&amp;theme-id=light&amp;default-tab=js,result">See the Pen JS-p2-05-basic-dom-node-properties-ex5 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	هل هناك فرق بين <code>tagName</code> و <code>nodeName</code>؟
</p>

<p>
	بالتأكيد، يظهر الفرق في اسميهما لكنّه في الحقيقة طفيف نوعا ما.
</p>

<ul>
<li>
		تكون خاصّيّة <code>tagName</code> للعقد العنصريّة فقط.
	</li>
	<li>
		تكون خاصّية <code>nodeName</code> مُعرّفةً في جميع العقد:
	</li>
	<li>
		بالنسبة للعناصر هي مماثلة لـ <code>tagName</code>.
	</li>
	<li>
		بالنسبة ﻷنواع العقد اﻷخرى (النصوص والتعليقات وغيرها) فهي سلسلة نصّيّة تحمل نوع العقدة.
	</li>
</ul>
<p>
	بعبارة أخرى، تُدعم <code>tagName</code> من العقد النصّيّة فقط (إذ أنّ منشأها من الصنف <code>Element</code>)، بينما تستطيع <code>nodeName</code> الإخبار عن أنواع العقد اﻷخرى.
</p>

<p>
	على سبيل المثال، لنوازن بين <code>tagName</code> و <code>nodeName</code> بتطبيقهما على كائن <code>document</code> وعلى عقدة تعليقيّة:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_3421_19" style="">
<span class="tag">&lt;body&gt;</span><span class="com">&lt;!-- comment --&gt;</span><span class="pln">

  </span><span class="tag">&lt;script&gt;</span><span class="pln">
    </span><span class="com">// بالنسبة للتعليق</span><span class="pln">
    alert</span><span class="pun">(</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">firstChild</span><span class="pun">.</span><span class="pln">tagName </span><span class="pun">);</span><span class="pln"> </span><span class="com">// undefined (not an element) -- (أي غير معرّف (ليس عنصرا</span><span class="pln">
    alert</span><span class="pun">(</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">firstChild</span><span class="pun">.</span><span class="pln">nodeName </span><span class="pun">);</span><span class="pln"> </span><span class="com">// #comment</span><span class="pln">

    </span><span class="com">// document بالنسبة لـ</span><span class="pln">
    alert</span><span class="pun">(</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">tagName </span><span class="pun">);</span><span class="pln"> </span><span class="com">// undefined (not an element)</span><span class="pln">
    alert</span><span class="pun">(</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">nodeName </span><span class="pun">);</span><span class="pln"> </span><span class="com">// #document</span><span class="pln">
  </span><span class="tag">&lt;/script&gt;</span><span class="pln">
</span><span class="tag">&lt;/body&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-05-basic-dom-node-properties-ex6" src="https://codepen.io/Hsoub/embed/preview/LYRwGbg?height=265&amp;theme-id=light&amp;default-tab=html,result">See the Pen JS-p2-05-basic-dom-node-properties-ex6 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	إذا اقتصرنا على التعامل مع العناصر فقط، فيمكننا استعمال كلٍّ من <code>tagName</code> و <code>nodeName</code> -- لا فرق بينهما.
</p>

<hr>
<p>
	<strong>يكون اسم الوسم دائما باﻷحرف الكبيرة (uppercase) ماعدا في وضع XML</strong>
</p>

<p>
	للمتصفّح وضعان لمعالجة المستندات: HTML و XML. يُستخدم وضع HTML عادة مع صفحات الويب. يُفًّعل وضع XML عندما يستقبل المتصفّح مستند XML بالترويسة <code>Content-Type: application/xml+xhtml</code>.
</p>

<p>
	في وضع HTML، تكون <code>tagName</code> و <code>nodeName</code> دائما باﻷحرف الكبيرة: فهي <code>BODY</code> سواء بالنسبة لـ <code>&lt;body&gt;</code> أو <code>&lt;BoDy&gt;</code>.
</p>

<p>
	في وضع XML، تُترك اﻷحرف "كما هي". في الوقت الحاضر، يندر استخدام وضع XML.
</p>

<hr>
<h2>
	innerHTML: المحتويات
</h2>

<p>
	تُمكّن <a href="https://w3c.github.io/DOM-Parsing/#widl-Element-innerHTML" rel="external nofollow">innerHTML</a> من تحصيل الـ HTML الذي بداخل العنصر على شكل سلسلة نصيّة. كما يمكننا أيضا التعديل عليه، مما يجعله من أقوى الطرق للتعديل على الصفحة.
</p>

<p>
	هذا المثال يبيّن كيفيّة عرض محتويات <code>document.body</code> ثم استبدالها كليّة:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_3421_21" style="">
<span class="tag">&lt;body&gt;</span><span class="pln">
  </span><span class="tag">&lt;p&gt;</span><span class="pln">A paragraph</span><span class="tag">&lt;/p&gt;</span><span class="pln">
  </span><span class="tag">&lt;div&gt;</span><span class="pln">A div</span><span class="tag">&lt;/div&gt;</span><span class="pln">

  </span><span class="tag">&lt;script&gt;</span><span class="pln">
    alert</span><span class="pun">(</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">innerHTML </span><span class="pun">);</span><span class="pln"> </span><span class="com">// قراءة المحتويات الحاليّة</span><span class="pln">
    document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">innerHTML </span><span class="pun">=</span><span class="pln"> </span><span class="str">'The new BODY!'</span><span class="pun">;</span><span class="pln"> </span><span class="com">// ثم استبدالها</span><span class="pln">
  </span><span class="tag">&lt;/script&gt;</span><span class="pln">

</span><span class="tag">&lt;/body&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-05-basic-dom-node-properties-ex7" src="https://codepen.io/Hsoub/embed/preview/bGwXEgE?height=265&amp;theme-id=light&amp;default-tab=html,result">See the Pen JS-p2-05-basic-dom-node-properties-ex7 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	يمكننا محاولة إدخال HTML غير سليم، ليقوم المتصفّح بتصحيح الأخطاء:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_3421_23" style="">
<span class="tag">&lt;body&gt;</span><span class="pln">

  </span><span class="tag">&lt;script&gt;</span><span class="pln">
    document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">innerHTML </span><span class="pun">=</span><span class="pln"> </span><span class="str">'&lt;b&gt;test'</span><span class="pun">;</span><span class="pln"> </span><span class="com">// نسينا إغلاق الوسم</span><span class="pln">
    alert</span><span class="pun">(</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">innerHTML </span><span class="pun">);</span><span class="pln"> </span><span class="com">// &lt;b&gt;test&lt;/b&gt; (صٌلّحت)</span><span class="pln">
  </span><span class="tag">&lt;/script&gt;</span><span class="pln">

</span><span class="tag">&lt;/body&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-05-basic-dom-node-properties-ex8" src="https://codepen.io/Hsoub/embed/preview/ZEpgQLJ?height=265&amp;theme-id=light&amp;default-tab=html,result">See the Pen JS-p2-05-basic-dom-node-properties-ex8 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<hr>
<p>
	<strong>لا تُنفّذ السكربتات</strong>
</p>

<p>
	إذا أدرجت <code>innerHTML</code> سكربت <code>&lt;script&gt;</code> في المستند، فإنّه يصير جزءًا من HTML لكنّه لا يُنفّذ.
</p>

<hr>
<h3>
	تعيد "=+innerHTML" الكتابة كليّة
</h3>

<p>
	يمكننا إضافة HTML إلى عنصر ما بواسطة <code>"elem.innerHTML+="more html</code> هكذا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3421_25" style="">
<span class="pln">chatDiv</span><span class="pun">.</span><span class="pln">innerHTML </span><span class="pun">+=</span><span class="pln"> </span><span class="str">"&lt;div&gt;Hello&lt;img src='smile.gif'/&gt; !&lt;/div&gt;"</span><span class="pun">;</span><span class="pln">
chatDiv</span><span class="pun">.</span><span class="pln">innerHTML </span><span class="pun">+=</span><span class="pln"> </span><span class="str">"How goes?"</span><span class="pun">;</span></pre>

<p>
	لكن يجب أن ننتبه عند فعل ذلك، فما يحدث فعلا ليست مجرّد إضافة، بل هي إعادة كتابة بالكليّة.
</p>

<p>
	ظاهريّا، يفعل هذان السطران نفس الشيء:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3421_27" style="">
<span class="pln">elem</span><span class="pun">.</span><span class="pln">innerHTML </span><span class="pun">+=</span><span class="pln"> </span><span class="str">"..."</span><span class="pun">;</span><span class="pln">
</span><span class="com">// :هو طريقة مختصرة لكتابة</span><span class="pln">
elem</span><span class="pun">.</span><span class="pln">innerHTML </span><span class="pun">=</span><span class="pln"> elem</span><span class="pun">.</span><span class="pln">innerHTML </span><span class="pun">+</span><span class="pln"> </span><span class="str">"..."</span></pre>

<p>
	بعبارة أخرى، ما تقوم به <code>=+innerHTML</code> هو التالي:
</p>

<ul>
<li>
		يُحذف المحتوى القديم.
	</li>
	<li>
		يُكتب في مكانه <code>innerHTML</code> الجديد (الذي هو سلسلة متكوّنة من المحتوى القديم والجديد).
	</li>
</ul>
<p>
	<strong>نتيجةً "لتصفير" المحتوى وإعادة كتابته من جديد، فإنّه يُعاد تحميل جميع الصّور وغيرها من الموارد.</strong>
</p>

<p>
	في مثال <code>chatDiv</code> أعلاه، يعيد السطر <code>?"chatDiv.innerHTML+="How goes</code> إنشاء محتوى HTML ثمّ يعيد تحميل الصّورة <code>smile.gif</code> (يُأمل أن تكون مخبّأةً في الذاكرة المؤقتة - Cache). إذا كان لدى <code>chatDiv</code> الكثير من النصوص والصور اﻷخرى، فإنّ إعادة التحميل تصير ظاهرة للعيان.
</p>

<p>
	هناك آثار جانبية أخرى كذلك. على سبيل المثال، إذا كان النصّ الموجود قد حُدّد بواسطة الفأرة، فإنّ معظم المتصفّحات ستزيل التحديد عنه عند إعادة كتابة <code>innerHTML</code> . كما أنّه إذا كان هناك <code>&lt;input&gt;</code> فيها نصّ أدخله الزائر، فإنّ النصّ سيُزال أيضا. إلى غير ذلك.
</p>

<p>
	لحسن الحظّ، هناك طرق أخرى لإضافة HTML عدا <code>innerHTML</code> ، سندرسها قريبا.
</p>

<h2>
	outerHTML: كامل HTML العنصر
</h2>

<p>
	تحتوي خاصّيّة <code>outerHTML</code> على كامل HTML العنصر. تشبه هذه الخاصّيّة <code>innerHTML</code> لكن بالإضافة إلى العنصر نفسه. إليك مثالا:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_3421_29" style="">
<span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"elem"</span><span class="tag">&gt;</span><span class="pln">Hello </span><span class="tag">&lt;b&gt;</span><span class="pln">World</span><span class="tag">&lt;/b&gt;&lt;/div&gt;</span><span class="pln">

</span><span class="tag">&lt;script&gt;</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln">elem</span><span class="pun">.</span><span class="pln">outerHTML</span><span class="pun">);</span><span class="pln"> </span><span class="com">// &lt;div id="elem"&gt;Hello &lt;b&gt;World&lt;/b&gt;&lt;/div&gt;</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-05-basic-dom-node-properties-ex9" src="https://codepen.io/Hsoub/embed/preview/LYRwGxg?height=265&amp;theme-id=light&amp;default-tab=html,result">See the Pen JS-p2-05-basic-dom-node-properties-ex9 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	<strong>انتبه: على خلاف <code>innerHTML</code>، لا يؤدي التعديل على <code>outerHTML</code> إلى تعديل العنصر، بل سيؤدي ذلك إلى استبداله في DOM.</strong>
</p>

<p>
	نعم، يبدو ذلك غريبا، وهو فعلا كذلك. لهذا خصصنا له تنبيها منفصلا هنا. ألقِ نظرة على هذا المثال:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_3421_31" style="">
<span class="tag">&lt;div&gt;</span><span class="pln">Hello, world!</span><span class="tag">&lt;/div&gt;</span><span class="pln">

</span><span class="tag">&lt;script&gt;</span><span class="pln">
  let div </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">'div'</span><span class="pun">);</span><span class="pln">

  </span><span class="com">//  &lt;p&gt;...&lt;/p&gt; بـ div.outerHTML استبدال </span><span class="pln">
  div</span><span class="pun">.</span><span class="pln">outerHTML </span><span class="pun">=</span><span class="pln"> </span><span class="str">'&lt;p&gt;A new element&lt;/p&gt;'</span><span class="pun">;</span><span class="pln"> </span><span class="com">// (*)</span><span class="pln">

  </span><span class="com">// على حاله 'div'  ياللجعب! بقي </span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln">div</span><span class="pun">.</span><span class="pln">outerHTML</span><span class="pun">);</span><span class="pln"> </span><span class="com">// &lt;div&gt;Hello, world!&lt;/div&gt; (**)</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-05-basic-dom-node-properties-ex10" src="https://codepen.io/Hsoub/embed/preview/MWjNKpo?height=265&amp;theme-id=light&amp;default-tab=html,result">See the Pen JS-p2-05-basic-dom-node-properties-ex10 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	يبدو ذلك غريبا، صحيح؟
</p>

<p>
	في السطر <code>(*)</code>، استبدلنا <code>&lt;div&gt;</code> بـ <code>&lt;p&gt;A new element&lt;/p&gt;</code>. في المستند الخارجي (DOM)، يمكننا ملاحظة المحتوى الجديد بدل <code>&lt;div&gt;</code>. لكن كما يمكن الملاحظة في السطر <code>(**)</code>، لم تتغيّر قيمة المتغيّر القديم <code>div</code>!
</p>

<p>
	لا يغيّر الإسنادُ <code>outerHTML</code> العنصرَ في DOM (في هذا المثال، الكائن الذي يشير إليه المتغير 'div')، لكنّه يحذفه من DOM ويدرج مكانه الـ HTML الجديد.
</p>

<p>
	فالذي حصل بفعل <code>...=div.outerHTML</code> هو ما يلي:
</p>

<ul>
<li>
		حُذف <code>div</code> من المستند.
	</li>
	<li>
		أُدرج في مكانه قطعة HTML أخرى <code>&lt;p&gt;A new element&lt;/p&gt;</code> .
	</li>
	<li>
		لا يزال لـ <code>div</code> نفس القيمة. ولم يُحفظ HTML الجديد في أيّ متغيّر.
	</li>
</ul>
<p>
	من السهل جدّا ارتكاب خطأ هنا: التعديل على <code>div.outerHTML</code> ثمّ مواصلة العمل بـ <code>div</code> وكأنّ فيه المحتوى الجديد. لكنّه ليس كذلك. ينطبق هذا على <code>innerHTML</code> لكن ليس على <code>outerHTML</code>.
</p>

<p>
	بإمكاننا التعديل على <code>elem.outerHTML</code>، لكن ينبغي التنبّه إلى أنّ ذلك لا يغيّر العنصر 'elem'، بل يضع مكانه HTML الجديد. يمكننا الحصول على مراجع للعناصر الجديدة من خلال البحث في DOM.
</p>

<h2>
	nodeValue/data: محتوى العقد النصية
</h2>

<p>
	لا تصلح الخاصّيّة <code>innerHTML</code> إلّا مع العقد العنصريّة.
</p>

<p>
	بالنسبة للعقد الأخرى، كالعقد النصّيّة، يقابل ذلك خاصّيّات <code>nodeValue</code> و <code>data</code>. هاتان الخاصّيّتان متماثلتان تقريبا في التطبيق، مع بعض الفروق الطفيفة في المواصفة. لذا سنستعمل <code>data</code> ﻷنّها أقصر.
</p>

<p>
	هذا مثالٌ لقراءة محتوى عقدة نصّيّة وتعليق:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_3421_33" style="">
<span class="tag">&lt;body&gt;</span><span class="pln">
  Hello
  </span><span class="com">&lt;!-- Comment --&gt;</span><span class="pln">
  </span><span class="tag">&lt;script&gt;</span><span class="pln">
    let text </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">firstChild</span><span class="pun">;</span><span class="pln">
    alert</span><span class="pun">(</span><span class="pln">text</span><span class="pun">.</span><span class="pln">data</span><span class="pun">);</span><span class="pln"> </span><span class="com">// Hello</span><span class="pln">

    let comment </span><span class="pun">=</span><span class="pln"> text</span><span class="pun">.</span><span class="pln">nextSibling</span><span class="pun">;</span><span class="pln">
    alert</span><span class="pun">(</span><span class="pln">comment</span><span class="pun">.</span><span class="pln">data</span><span class="pun">);</span><span class="pln"> </span><span class="com">// Comment</span><span class="pln">
  </span><span class="tag">&lt;/script&gt;</span><span class="pln">
</span><span class="tag">&lt;/body&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-05-basic-dom-node-properties-ex11" src="https://codepen.io/Hsoub/embed/preview/JjRgGWB?height=265&amp;theme-id=light&amp;default-tab=html,result">See the Pen JS-p2-05-basic-dom-node-properties-ex11 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	يمكننا تصوّر دافعٍ لقراءة وتعديل العقد النصّيّة، لكن لماذا التعليقات؟
</p>

<p>
	يُضمّن فيها المطوّرون أحيانا معلومات أو تعليمات متعلّقة بالقالب في HTML، على هذا النحو:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_3421_35" style="">
<span class="com">&lt;!-- if isAdmin --&gt;</span><span class="pln">
  </span><span class="tag">&lt;div&gt;</span><span class="pln">Welcome, Admin!</span><span class="tag">&lt;/div&gt;</span><span class="pln">
</span><span class="com">&lt;!-- /if --&gt;</span></pre>

<p>
	… فيمكن لجافاسكربت قراءتها من خلال خاصّيّة <code>data</code> ثمّ معالجة التعليمات التي تتضمّنها.
</p>

<h2>
	textContent: نص محض
</h2>

<p>
	تتيح خاصّية <code>textContent</code> الوصول إلى <em>النصّ</em> الذي بداخل العنصر: مجرّد النصّ، دون أيّة وسوم.
</p>

<p>
	على سبيل المثال:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_3421_37" style="">
<span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"news"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;h1&gt;</span><span class="pln">Headline!</span><span class="tag">&lt;/h1&gt;</span><span class="pln">
  </span><span class="tag">&lt;p&gt;</span><span class="pln">Martians attack people!</span><span class="tag">&lt;/p&gt;</span><span class="pln">
</span><span class="tag">&lt;/div&gt;</span><span class="pln">

</span><span class="tag">&lt;script&gt;</span><span class="pln">
  </span><span class="com">// Headline! Martians attack people!</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln">news</span><span class="pun">.</span><span class="pln">textContent</span><span class="pun">);</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-05-basic-dom-node-properties-ex12" src="https://codepen.io/Hsoub/embed/preview/mdrNVWZ?height=265&amp;theme-id=light&amp;default-tab=html,result">See the Pen JS-p2-05-basic-dom-node-properties-ex12 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	كما يمكن أن نلاحظ، أُعيد النصّ فقط، وكأنّ جميع الـوسوم قُطعت، وبقي النصّ الذي بداخلها.
</p>

<p>
	عمليّا، يندر أن يُحتاج إلى قراءة مثل هذا النصّ.
</p>

<p>
	<strong>يعدّ التعديل على <code>textContent</code> مفيدا أكثر بكثير، لأنّه يمكّن من كتابة النصوص على "النحو الآمن".</strong>
</p>

<p>
	لنتفرض أن لدينا سلسلة نصّيّة ما، أدخلها مستخدمٌ مثلا، ونريد أن نعرضها.
</p>

<ul>
<li>
		باستخدام <code>innerHTML</code> سندرجها "على شكل HTML"، بجميع وسوم HTML.
	</li>
	<li>
		باستخدام <code>textContent</code> سندرجها "على شكل نصّ"، وتُعامل جميع الرموز معاملة حرفيّة.
	</li>
</ul>
<p>
	قارن بين الإثنين:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3421_39" style="">
<span class="pun">&lt;</span><span class="pln">div id</span><span class="pun">=</span><span class="str">"elem1"</span><span class="pun">&gt;&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&lt;</span><span class="pln">div id</span><span class="pun">=</span><span class="str">"elem2"</span><span class="pun">&gt;&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">

</span><span class="pun">&lt;</span><span class="pln">script</span><span class="pun">&gt;</span><span class="pln">
  let name </span><span class="pun">=</span><span class="pln"> prompt</span><span class="pun">(</span><span class="str">"What's your name?"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"&lt;b&gt;Winnie-the-pooh!&lt;/b&gt;"</span><span class="pun">);</span><span class="pln">

  elem1</span><span class="pun">.</span><span class="pln">innerHTML </span><span class="pun">=</span><span class="pln"> name</span><span class="pun">;</span><span class="pln">
  elem2</span><span class="pun">.</span><span class="pln">textContent </span><span class="pun">=</span><span class="pln"> name</span><span class="pun">;</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-05-basic-dom-node-properties-ex13" src="https://codepen.io/Hsoub/embed/preview/poEMgPe?height=265&amp;theme-id=light&amp;default-tab=html,result">See the Pen JS-p2-05-basic-dom-node-properties-ex13 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<ol>
<li>
		يحصُل <code>&lt;div&gt;</code> اﻷوّل على الاسم (name) "على شكل HTML": جميع الوسوم تُعامل كوسوم، ونرى بذلك الاسم بخطّ عريض (bold).
	</li>
	<li>
		يحصُل <code>&lt;div&gt;</code> الثاني على الاسم "على شكل نصّ"، فنرى حرفيًّا <code>&lt;b&gt;Winnie-the-pooh!&lt;/b&gt;</code>.
	</li>
</ol>
<p>
	في أغلب الحالات، نتوقّع من المستخدم أن يدخل نصًّا، ونريد أن نعامله كنصّ. لا نريد HTML غير متوقّع في موقعنا. وهذا ما يفعله الإسناد إلى <code>textContent</code> بالضبط.
</p>

<h2>
	خاصية 'hidden'
</h2>

<p>
	تُحدّد السّمة "hidden" وخاصيّة DOM التي تحمل نفس الاسم ما إذا كان العنصر مرئيّا أو لا.
</p>

<p>
	بإمكاننا استخدامها في HTML أو إسنادها في جافاسكربت كالتالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_3421_43" style="">
<span class="tag">&lt;div&gt;</span><span class="pln">Both divs below are hidden</span><span class="tag">&lt;/div&gt;</span><span class="pln">

</span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">hidden</span><span class="tag">&gt;</span><span class="pln">With the attribute "hidden"</span><span class="tag">&lt;/div&gt;</span><span class="pln">

</span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"elem"</span><span class="tag">&gt;</span><span class="pln">JavaScript assigned the property "hidden"</span><span class="tag">&lt;/div&gt;</span><span class="pln">

</span><span class="tag">&lt;script&gt;</span><span class="pln">
  elem</span><span class="pun">.</span><span class="pln">hidden </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-05-basic-dom-node-properties-ex14" src="https://codepen.io/Hsoub/embed/GRjVoEK?height=265&amp;theme-id=light&amp;default-tab=html,result">See the Pen JS-p2-05-basic-dom-node-properties-ex14 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	مبدئيّا، تعمل <code>hidden</code> تماما مثل <code>"style="display:none</code> ، لكنّها أقصر في الكتابة.
</p>

<p>
	إليك عنصرا وامضًا:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_3421_45" style="">
<span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"elem"</span><span class="tag">&gt;</span><span class="pln">A blinking element</span><span class="tag">&lt;/div&gt;</span><span class="pln">

</span><span class="tag">&lt;script&gt;</span><span class="pln">
  setInterval</span><span class="pun">(()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> elem</span><span class="pun">.</span><span class="pln">hidden </span><span class="pun">=</span><span class="pln"> </span><span class="pun">!</span><span class="pln">elem</span><span class="pun">.</span><span class="pln">hidden</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1000</span><span class="pun">);</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="242" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-05-basic-dom-node-properties-ex15" src="https://codepen.io/Hsoub/embed/preview/KKgOVqW?height=242&amp;theme-id=light&amp;default-tab=html,result">See the Pen JS-p2-05-basic-dom-node-properties-ex15 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<h2>
	المزيد من الخاصيات
</h2>

<p>
	للعناصر في DOM المزيد من الخاصّيّات، خصوصا تلك التي تتعلق باﻷصناف:
</p>

<ul>
<li>
		<code>value</code> -- القيمة التي في <code>&lt;input&gt;</code> و <code>&lt;select&gt;</code> و <code>&lt;textarea&gt;</code> (المتعلقة بـ <code>HTMLInputElement</code> و <code>HTMLSelectElement</code> …).
	</li>
	<li>
		<code>href</code> -- قيمة "href" في <code>&lt;"..."=a href&gt;</code> (المتعلقة بـ <code>HTMLAnchorElement</code>).
	</li>
	<li>
		<code>id</code> -- قيمة السمة "id" لجميع العناصر (المتعلقة بـ<code>HTMLElement</code>).
	</li>
	<li>
		… والمزيد من ذلك…
	</li>
</ul>
<p>
	على سبيل المثال:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_3421_47" style="">
<span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"text"</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"elem"</span><span class="pln"> </span><span class="atn">value</span><span class="pun">=</span><span class="atv">"value"</span><span class="tag">&gt;</span><span class="pln">

</span><span class="tag">&lt;script&gt;</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln">elem</span><span class="pun">.</span><span class="pln">type</span><span class="pun">);</span><span class="pln"> </span><span class="com">// "text"</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln">elem</span><span class="pun">.</span><span class="pln">id</span><span class="pun">);</span><span class="pln"> </span><span class="com">// "elem"</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln">elem</span><span class="pun">.</span><span class="pln">value</span><span class="pun">);</span><span class="pln"> </span><span class="com">// value</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-05-basic-dom-node-properties-ex16" src="https://codepen.io/Hsoub/embed/preview/ExgqPXL?height=265&amp;theme-id=light&amp;default-tab=html,result">See the Pen JS-p2-05-basic-dom-node-properties-ex16 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	تقابل معظم السمات القياسية في HTML خاصّيات في DOM، ويمكننا الوصول إليها بهذه الطريقة.
</p>

<p>
	إذا أردنا معرفة جميع الخاصّيّات المدعومة في صنف معيّن، يمكننا الاطلاع عليها في المواصفة. على سبيل المثال، <code>HTMLInputElement</code> موثّقة <a href="https://html.spec.whatwg.org/#htmlinputelement" rel="external nofollow">هنا</a>.
</p>

<p>
	أمّا إذا أردنا الحصول عليها بسرعة، أو كنّا مهتمين بمواصفة ملموسة في المتصفّح، يمكننا استعراض العنصر بواسطة <code>(console.dir(elem</code> لقراءة الخاصّيّات. أو يمكن كذلك استكشاف "خاصّيّات DOM" في لسان العناصر (Elements) في أدوات المطوّر في المتصفّح.
</p>

<h2>
	الملخص
</h2>

<p>
	تنتمي كلّ عقدة في DOM إلى صنف معيّن. تشكّل اﻷصناف تسلسلا هرميّا. يكون مجموع الخاصّيّات والتوابع التي لدى عقدة ما ناتجا عن الوراثة.
</p>

<p>
	خاصّيّات عقد DOM الرئيسيّة هي:
</p>

<ul>
<li>
		<code>nodeType</code>: يمكننا استعمالها لمعرفة ما إذا كانت العقدة نصيّة أو عنصريّة. لها القيمة العددية: <code>1</code> للعناصر و <code>3</code> للعقد النصّيّة، وبعض القيم اﻷخرى لباقي أنواع العقد. يمكن قراءتها فقط.
	</li>
	<li>
		<code>nodeName/tagName</code>: للعناصر <code>tagName</code> (تُكتب باﻷحرف الكبيرة ماعدا في وضع XML)، وللعقد غير العنصريّة <code>nodeName</code>. تُبيّن ماهية العقدة. يمكن قراءتها فقط.
	</li>
	<li>
		<code>innerHTML</code>: ما يحتويه العنصر من HTML. يمكن التعديل عليها.
	</li>
	<li>
		<code>outerHTML</code>: كامل HTML العنصر. لا تمسّ عمليّة التعديل على <code>elem.outerHTML</code> العنصر <code>elem</code> نفسه، لكن تستبدله بالـ HTML الجديد في DOM.
	</li>
	<li>
		<code>nodeValue/data</code>: محتوى العقد غير العنصريّة (النصوص والتعليقات). هاتان الخاصّيّتان متماثلتان تقريبا، لكن تُستعمل في العادة <code>data</code> . يمكن التعديل عليها.
	</li>
	<li>
		<code>textContent</code>: النصّ الذي بداخل العنصر: HTML منزوع الوسوم. يضع التعديلُ عليه النصَّ بداخل العنصر، مع معاملة جميع المحرّفات الخاصّة والوسوم كمجرّد نصّ. تُمكّن من إدراج النصوص التي يُدخلها المستخدمون بطريقة آمنة تحمي من إدراج HTML غير مرغوب فيه.
	</li>
	<li>
		<code>hidden</code>: عند إعطائها القيمة <code>true</code> تؤدّي نفس وظيفة <code>display:none</code> في CSS.
	</li>
</ul>
<p>
	تملك عقد DOM المزيد من الخاصّيّات بحسب الصنف الذي تنتمي إليه. على سبيل المثال، تدعم العناصر <code>&lt;input&gt;</code> (ذات الصنف <code>HTMLInputElement</code>) كلاّ من <code>value</code> و <code>type</code> ، بينما تدعم <code>&lt;a&gt;</code> (ذات الصنف <code>HTMLAnchorElement</code>) الخاصيّة <code>href</code> ، إلى غير ذلك. لمُعظم السمات القياسية في HTML خاصيّة تقابلها في DOM.
</p>

<p>
	لكن مع ذلك، لا تتساوى سمات HTML وخاصيّات DOM على الدوام، كما سنرى في المقال التالي.
</p>

<hr>
<h2>
	التمارين
</h2>

<h3>
	حساب الفروع
</h3>

<p>
	اﻷهميّة: 5
</p>

<p>
	هناك شجرة متشكّلة من تفرّع العناصر <code>ul/li</code>.
</p>

<p>
	اكتب الشفرة التي من أجل كل <code>&lt;li&gt;</code> تستعرض التالي:
</p>

<ol>
<li>
		النصّ الذي بداخله (دون الشجرة الفرعيّة).
	</li>
	<li>
		عدد الـ <code>&lt;li&gt;</code> المتفرّعة عنه -- جميع العقد السليلة، بما في ذلك العقد المتفرّعة عن فروعه إلى آخر ذلك.
	</li>
</ol>
<p>
	<a href="https://en.js.cx/task/tree-info/solution/" rel="external nofollow">افتح المثال في نافذة مستقلة</a>
</p>

<p>
	<a href="https://plnkr.co/edit/KQWTwzSfogX1OLJV?p=preview&amp;preview" rel="external nofollow">افتح البيئة التجريبيّة لإنجاز التمرين</a>
</p>

<h3>
	الحل
</h3>

<p>
	لنعمل حلقة تكراريّة حول جميع الـ <code>&lt;li&gt;</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3421_50" style="">
<span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let li of document</span><span class="pun">.</span><span class="pln">querySelectorAll</span><span class="pun">(</span><span class="str">'li'</span><span class="pun">))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="pun">...</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	نحتاج في الحلقة أن نحصل على النصّ بداخل كلّ <code>li</code>.
</p>

<p>
	يمكننا قراءة النصّ الذي بداخل أوّل العقد اﻷبناء لـ <code>li</code> ، والتي هي العقدة النصّيّة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3421_52" style="">
<span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let li of document</span><span class="pun">.</span><span class="pln">querySelectorAll</span><span class="pun">(</span><span class="str">'li'</span><span class="pun">))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  let title </span><span class="pun">=</span><span class="pln"> li</span><span class="pun">.</span><span class="pln">firstChild</span><span class="pun">.</span><span class="pln">data</span><span class="pun">;</span><span class="pln">

  </span><span class="com">// الذي يأتي قبل باقي العقد &lt;li&gt; هو النصّ داخل title  </span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	بعدها يمكننا الحصول على عدد العقد السليلة باستخدام <code>li.getElementsByTagName('li').length</code>.
</p>

<p>
	<a href="https://plnkr.co/edit/JdHPZiU1xL70V3Qw?p=preview" rel="external nofollow">افتح الحلّ في البيئة التجريبيّة</a>
</p>

<hr>
<h3>
	مالذي بداخل nodeType؟
</h3>

<p>
	الأهميّة: 5
</p>

<p>
	ماذا يعرض السكربت التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_3421_54" style="">
<span class="tag">&lt;html&gt;</span><span class="pln">

</span><span class="tag">&lt;body&gt;</span><span class="pln">
  </span><span class="tag">&lt;script&gt;</span><span class="pln">
    alert</span><span class="pun">(</span><span class="pln">document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">lastChild</span><span class="pun">.</span><span class="pln">nodeType</span><span class="pun">);</span><span class="pln">
  </span><span class="tag">&lt;/script&gt;</span><span class="pln">
</span><span class="tag">&lt;/body&gt;</span><span class="pln">

</span><span class="tag">&lt;/html&gt;</span></pre>

<h3>
	الحل
</h3>

<p>
	توجد خدعة هنا.
</p>

<p>
	في الوقت الذي يُنفّذ فيه <code>&lt;script&gt;</code> ، تكون آخر العقد في DOM هي <code>&lt;script&gt;</code> نفسه، ﻷنّ المتصفّح لم يكن قد عالج بقيّة الصفحة بعد.
</p>

<p>
	إذا الجواب هو <code>1</code> (عقدة عنصريّة).
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_3421_56" style="">
<span class="tag">&lt;html&gt;</span><span class="pln">

</span><span class="tag">&lt;body&gt;</span><span class="pln">
  </span><span class="tag">&lt;script&gt;</span><span class="pln">
    alert</span><span class="pun">(</span><span class="pln">document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">lastChild</span><span class="pun">.</span><span class="pln">nodeType</span><span class="pun">);</span><span class="pln">
  </span><span class="tag">&lt;/script&gt;</span><span class="pln">
</span><span class="tag">&lt;/body&gt;</span><span class="pln">

</span><span class="tag">&lt;/html&gt;</span></pre>

<hr>
<h3>
	وسم في التعليق
</h3>

<p>
	اﻷهميّة: 3
</p>

<p>
	ماذا تعرض هذه الشفرة:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_3421_58" style="">
<span class="tag">&lt;script&gt;</span><span class="pln">
  let body </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">;</span><span class="pln">

  body</span><span class="pun">.</span><span class="pln">innerHTML </span><span class="pun">=</span><span class="pln"> </span><span class="str">"&lt;!--"</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> body</span><span class="pun">.</span><span class="pln">tagName </span><span class="pun">+</span><span class="pln"> </span><span class="str">"--&gt;"</span><span class="pun">;</span><span class="pln">

  alert</span><span class="pun">(</span><span class="pln"> body</span><span class="pun">.</span><span class="pln">firstChild</span><span class="pun">.</span><span class="pln">data </span><span class="pun">);</span><span class="pln"> </span><span class="com">// ماذا هنا؟</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<h3>
	الحل
</h3>

<p>
	الجواب هو، <strong><code>BODY</code></strong>
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_3421_60" style="">
<span class="tag">&lt;script&gt;</span><span class="pln">
  let body </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">;</span><span class="pln">

  body</span><span class="pun">.</span><span class="pln">innerHTML </span><span class="pun">=</span><span class="pln"> </span><span class="str">"&lt;!--"</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> body</span><span class="pun">.</span><span class="pln">tagName </span><span class="pun">+</span><span class="pln"> </span><span class="str">"--&gt;"</span><span class="pun">;</span><span class="pln">

  alert</span><span class="pun">(</span><span class="pln"> body</span><span class="pun">.</span><span class="pln">firstChild</span><span class="pun">.</span><span class="pln">data </span><span class="pun">);</span><span class="pln"> </span><span class="com">// BODY</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	الذي يحصل خطوة بخطوة:
</p>

<ol>
<li>
		يُستبدل محتوى <code>&lt;body&gt;</code> بالتعليق. التعليق هو <code>&lt;--BODY--!&gt;</code> ، لأنّ <code>"body.tagName == "BODY</code>. كما نذكر، يٌكتب <code>tagName</code> دائما بالأحرف الكبيرة في HTML.
	</li>
	<li>
		التعليق الآن هو الابن الوحيد، فنحصل عليه بواسطة <code>body.firstChild</code>.
	</li>
	<li>
		تكون خاصّيّة <code>data</code> بالنسبة للتعليق هي محتواه (ما بداخل <code>&lt;--...--!&gt;</code>): <code>"BODY"</code>.
	</li>
</ol>
<hr>
<h3>
	أين يقع "المستند" في التسلسل الهرمي:
</h3>

<p>
	اﻷهميّة: 4
</p>

<p>
	ما هو الصنف الذي ينتمي إليه <code>document</code> ؟
</p>

<p>
	ما هو مكانه في التسلسل الهرميّ لـ DOM ؟
</p>

<p>
	هل يرث من <code>Node</code> أو <code>Element</code> أو ربّما <code>HTMLElement</code> ؟
</p>

<h3>
	الحل
</h3>

<p>
	يمكننا معرفة الصنف الذي ينتمي إليه من خلال عرضها هكذا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3421_62" style="">
<span class="pln">alert</span><span class="pun">(</span><span class="pln">document</span><span class="pun">);</span><span class="pln"> </span><span class="com">// [object HTMLDocument]</span></pre>

<p>
	أو:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3421_64" style="">
<span class="pln">alert</span><span class="pun">(</span><span class="pln">document</span><span class="pun">.</span><span class="pln">constructor</span><span class="pun">.</span><span class="pln">name</span><span class="pun">);</span><span class="pln"> </span><span class="com">// HTMLDocument</span></pre>

<p>
	إذًا <code>document</code> هو نسخة من الصنف <code>HTMLDocument</code>.
</p>

<p>
	ما هو مكانه في التسلسل الهرميّ ؟
</p>

<p>
	نعم، يمكننا تصفّح المواصفة، لكن سيكون أسرع لو اكتشفنا ذلك يدويّا.
</p>

<p>
	لنجتز سلسلة prototype بواسطة <code>__proto__</code>.
</p>

<p>
	كما نعلم، توجد توابع الصنف في <code>prototype</code> الدالة البانية. على سبيل المثال، توجد توابع المستندات في <code>HTMLDocument.prototype</code>.
</p>

<p>
	بالإضافة إلى ذلك، هناك مرجعٌ إلى الدالة البانية بداخل <code>prototype</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3421_66" style="">
<span class="pln">alert</span><span class="pun">(</span><span class="typ">HTMLDocument</span><span class="pun">.</span><span class="pln">prototype</span><span class="pun">.</span><span class="pln">constructor </span><span class="pun">===</span><span class="pln"> </span><span class="typ">HTMLDocument</span><span class="pun">);</span><span class="pln"> </span><span class="com">// true</span></pre>

<p>
	للحصول على اسم الصنف على شكل سلسلة نصيّة، يمكننا استخدام <code>constructor.name</code>. لنفعل ذلك مع جميع سلسلة prototype الخاصّة بـ <code>document</code> إلى غاية الصنف <code>Node</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3421_68" style="">
<span class="pln">alert</span><span class="pun">(</span><span class="typ">HTMLDocument</span><span class="pun">.</span><span class="pln">prototype</span><span class="pun">.</span><span class="pln">constructor</span><span class="pun">.</span><span class="pln">name</span><span class="pun">);</span><span class="pln"> </span><span class="com">// HTMLDocument</span><span class="pln">
alert</span><span class="pun">(</span><span class="typ">HTMLDocument</span><span class="pun">.</span><span class="pln">prototype</span><span class="pun">.</span><span class="pln">__proto__</span><span class="pun">.</span><span class="pln">constructor</span><span class="pun">.</span><span class="pln">name</span><span class="pun">);</span><span class="pln"> </span><span class="com">// Document</span><span class="pln">
alert</span><span class="pun">(</span><span class="typ">HTMLDocument</span><span class="pun">.</span><span class="pln">prototype</span><span class="pun">.</span><span class="pln">__proto__</span><span class="pun">.</span><span class="pln">__proto__</span><span class="pun">.</span><span class="pln">constructor</span><span class="pun">.</span><span class="pln">name</span><span class="pun">);</span><span class="pln"> </span><span class="com">// Node</span></pre>

<p>
	هذا هو التسلسل الهرميّ.
</p>

<p>
	يمكننا كذلك تفحّص الكائن باستخدام <code>(console.dir(document</code> ثم معرفة هذه اﻷسماء من خلال فتح <code>__proto__</code>. تأخذ الطرفيّة هذه اﻷسماء من <code>constructor</code> داخليّا.
</p>

<hr>
<p>
	ترجمة وبتصرف لمقال <a href="https://javascript.info/basic-dom-node-properties" rel="external nofollow">Node properties: type, tag and contents</a> من كتاب <a href="https://javascript.info/" rel="external nofollow">The Modern JavaScript Tutorial</a>.
</p>
]]></description><guid isPermaLink="false">1107</guid><pubDate>Mon, 25 Jan 2021 13:00:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x628;&#x62D;&#x62B; &#x641;&#x64A; DOM &#x639;&#x628;&#x631; *getElement &#x648; *querySelector &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A;</title><link>https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%A8%D8%AD%D8%AB-%D9%81%D9%8A-dom-%D8%B9%D8%A8%D8%B1-getelement-%D9%88-queryselector-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r1106/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_01/600fe5dd7708c_--get-element.png.53ce09a204174fe6d54ec04500bce814.png" /></p>

<p>
	تُفيد خصائص التنقّل في DOM كثيرا عندما تكون العناصر قريبة من بعضها البعض. لكن ماذا لو لم تكن كذلك؟ كيف يمكن تحصيل عنصرٍ ما على الصفحة؟
</p>

<p>
	هناك المزيد من توابع البحث لهذا الغرض.
</p>

<h2>
	document.getElementById أو فقط id
</h2>

<p>
	إذا كان للعنصر سمة <code>id</code>، فيمكننا تحصيله باستخدام التابع <code>(document.getElementById(id</code>، أينما وُجد.
</p>

<p>
	على سبيل المثال:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1573_9" style="">
<span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"elem"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"elem-content"</span><span class="tag">&gt;</span><span class="pln">Element</span><span class="tag">&lt;/div&gt;</span><span class="pln">
</span><span class="tag">&lt;/div&gt;</span><span class="pln">

</span><span class="tag">&lt;script&gt;</span><span class="pln">
  </span><span class="com">// تحصيل العنصر</span><span class="pln">
  let elem </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">'elem'</span><span class="pun">);</span><span class="pln">

  </span><span class="com">// تلوين خلفيّته باﻷحمر</span><span class="pln">
  elem</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">background </span><span class="pun">=</span><span class="pln"> </span><span class="str">'red'</span><span class="pun">;</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" src="https://codepen.io/Hsoub/embed/PoGMPXL?height=265&amp;theme-id=light&amp;default-tab=html,result" style="width: 100%;" title="JS-p2-04-searching-elements-dom-ex01">See the Pen JS-p2-04-searching-elements-dom-ex01 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	بالإضافة إلى هذا، يمكن الإشارة إلى العنصر بواسطة متغيّر عامّ (global variable) اسمه نفس قيمة الـ <code>id</code>.
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1573_11" style="">
<span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"elem"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"elem-content"</span><span class="tag">&gt;</span><span class="pln">Element</span><span class="tag">&lt;/div&gt;</span><span class="pln">
</span><span class="tag">&lt;/div&gt;</span><span class="pln">

</span><span class="tag">&lt;script&gt;</span><span class="pln">
  </span><span class="com">// id="elem" الذي سمته DOM إلى عنصر elem يشير المتغيّر</span><span class="pln">
  elem</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">background </span><span class="pun">=</span><span class="pln"> </span><span class="str">'red'</span><span class="pun">;</span><span class="pln">

  </span><span class="com">// واصلة في وسطه، لذا فلا يمكن أن يكون اسمًا لمتغير id="elem-content"لدى</span><span class="pln">
  </span><span class="com">// window['elem-content'] لكن يمكن الوصول إليه بواسطة اﻷقواس المربعة...</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" src="https://codepen.io/Hsoub/embed/BaLXove?height=265&amp;theme-id=light&amp;default-tab=html,result" style="width: 100%;" title="JS-p2-04-searching-elements-dom-ex02">See the Pen JS-p2-04-searching-elements-dom-ex02 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	… هذا إذا لم نصرّح بمتغيّر جافاسكربت له نفس الاسم، فإنّ اﻷولويّة حينها تكون له:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1573_13" style="">
<span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"elem"</span><span class="tag">&gt;&lt;/div&gt;</span><span class="pln">

</span><span class="tag">&lt;script&gt;</span><span class="pln">
  let elem </span><span class="pun">=</span><span class="pln"> </span><span class="lit">5</span><span class="pun">;</span><span class="pln"> </span><span class="com">//  &lt;div id="elem"&gt; هو 5، وليس إشارة إلى elem يكون الآن</span><span class="pln">

  alert</span><span class="pun">(</span><span class="pln">elem</span><span class="pun">);</span><span class="pln"> </span><span class="com">// 5</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" src="https://codepen.io/Hsoub/embed/preview/mdrNeva?height=265&amp;theme-id=light&amp;default-tab=html,result" style="width: 100%;" title="JS-p2-04-searching-elements-dom-ex03">See the Pen JS-p2-04-searching-elements-dom-ex03 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<hr>
<p>
	<strong>يُرجى عدم استخدام المتغيّرات العامّة المسمّات على قيم الـ id للوصول إلى العناصر</strong>
</p>

<p>
	هذا السلوك مُبيّن في <a href="https://html.spec.whatwg.org/#dom-window-nameditem" rel="external nofollow">المواصفة</a>، مما يجعله وفق المعايير نوعا ما. لكنّه مدعوم في الغالب بغرض التوافق (compatibility).
</p>

<p>
	يحاول المتصفّح مساعدتنا بالمزج بين مجالات اﻷسماء (namespaces) في جافاسكربت و DOM. لا بأس بذلك في النصوص البرمجيّة البسيطة المضّمنة في HTML، لكن لا يُنصح به في العموم. فقد يؤدي ذلك إلى تناقضات في التسمية. كما أنّه عند قراءة شفرة جافاسكربت دون النظر إلى HTML، قد لا يتضّح من أين يأتي المتغيّر.
</p>

<p>
	نستعمل هنا في هذا المقال <code>id</code> للإشارة مباشرة إلى عنصر ما بغرض الاختصار، عندما يكون واضحا من أين يأتي العنصر.
</p>

<p>
	في التطبيقات الواقعيّة، تُعدّ <code>document.getElementById</code> هي الطريقة المفضّلة.
</p>

<hr>
<hr>
<p>
	<strong>يجب أن يكون الـ <code>id</code> فريدًا</strong>
</p>

<p>
	يجب أن يكون الـ <code>id</code> فريدًا. لا يمكن أن يحمل أكثر من عنصر في المستند نفس الـ <code>id</code>.
</p>

<p>
	إذا كانت هناك عدّة عناصر لها نفس الـ <code>id</code> ، فإنّه لا يمكن التنبؤ بسلوك التوابع التي تستخدمها. فقد تُرجع مثلا <code>document.getElementById</code> أيًّا من العناصر عشوائيًّا. لذا يُرجى الالتزام بالقاعدة وإبقاء الـ <code>id</code> فريدا.
</p>

<hr>
<hr>
<p>
	<strong><code>document.getElementById</code> فقط، وليس <code>anyElem.getElementById</code></strong>
</p>

<p>
	يمكن استدعاء التابع <code>getElementById</code> على الكائن <code>document</code> فقط. يبحث هذا التابع عن الـ <code>id</code> المراد في المستند بأكمله.
</p>

<hr>
<h2>
	querySelectorAll
</h2>

<p>
	يُعدّ <code>(css)elem.querySelectorAll</code> أكثر التوابع تنوّعا في الاستخدام على الإطلاق. يعيد هذا التابع جميع العناصر التي ينطبق عليها محدّد selector) CSS) معيّن.
</p>

<p>
	نبحث في اﻷسفل مثلا عن جميع العناصر <code>&lt;li&gt;</code> التي هي آخر اﻷبناء:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1573_15" style="">
<span class="tag">&lt;ul&gt;</span><span class="pln">
  </span><span class="tag">&lt;li&gt;</span><span class="pln">The</span><span class="tag">&lt;/li&gt;</span><span class="pln">
  </span><span class="tag">&lt;li&gt;</span><span class="pln">test</span><span class="tag">&lt;/li&gt;</span><span class="pln">
</span><span class="tag">&lt;/ul&gt;</span><span class="pln">
</span><span class="tag">&lt;ul&gt;</span><span class="pln">
  </span><span class="tag">&lt;li&gt;</span><span class="pln">has</span><span class="tag">&lt;/li&gt;</span><span class="pln">
  </span><span class="tag">&lt;li&gt;</span><span class="pln">passed</span><span class="tag">&lt;/li&gt;</span><span class="pln">
</span><span class="tag">&lt;/ul&gt;</span><span class="pln">
</span><span class="tag">&lt;script&gt;</span><span class="pln">
  let elements </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">querySelectorAll</span><span class="pun">(</span><span class="str">'ul &gt; li:last-child'</span><span class="pun">);</span><span class="pln">

  </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let elem of elements</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    alert</span><span class="pun">(</span><span class="pln">elem</span><span class="pun">.</span><span class="pln">innerHTML</span><span class="pun">);</span><span class="pln"> </span><span class="com">// "test", "passed"</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" src="https://codepen.io/Hsoub/embed/preview/mdrNeoa?height=265&amp;theme-id=light&amp;default-tab=html,result" style="width: 100%;" title="JS-p2-04-searching-elements-dom-ex04">See the Pen JS-p2-04-searching-elements-dom-ex04 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	هذا التابع قويّ بالفعل، ﻷنّه يمكن معه استخدام أيّ محدّد CSS.
</p>

<hr>
<p>
	<strong>يمكن استخدام أشباه اﻷصناف كذلك</strong>
</p>

<p>
	يدعم محدّد CSS أيضا أشباه اﻷصناف (pseudo-class) مثل <code>hover:</code> و <code>active:</code>. على سبيل المثال، يعيد <code>('document.querySelectorAll(':hover</code> مجموعة العناصر التي يوجد عليها المؤشّر حاليّا (حسب ترتيب تفرعها: بداية من <code>&lt;html&gt;</code> إلى آخر فرع منها).
</p>

<hr>
<h2>
	querySelector
</h2>

<p>
	يعيد استدعاء <code>(elem.querySelector(css</code> أوّل العناصر التي ينطبق عليها محدّد CSS.
</p>

<p>
	بعبارة أخرى، هي نفس نتيجة <code>[elem.querySelectorAll(css)[0</code> ، لكنّ هذه اﻷخيرة تبحث عن <em>جميع</em> العناصر وتختار بعد ذلك أوّلها، بينما تبحث <code>elem.querySelector</code> عن عنصر واحد فقط. فهي بذلك أسرع في البحث وأقصر في الكتابة.
</p>

<h2>
	matches
</h2>

<p>
	تقوم التوابع السابقة بالبحث في DOM.
</p>

<p>
	لا يقوم <a href="http://dom.spec.whatwg.org/#dom-element-matches" rel="external nofollow">(elem.matches(css</a> بالبحث عن أيّ شيء، بل يتحقّق فقط من أنّ العنصر <code>elem</code> يطابق محدّد CSS المراد، ويعيد إمّا <code>true</code> أو <code>false</code>.
</p>

<p>
	يُفيد هذا التابع عند المرور على عدد من العناصر (في مصفوفة أو شيء من هذا القبيل) ونريد ترشيح العناصر التي تهمّنا فقط.
</p>

<p>
	على سبيل المثال:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1573_17" style="">
<span class="tag">&lt;a</span><span class="pln"> </span><span class="atn">href</span><span class="pun">=</span><span class="atv">"http://example.com/file.zip"</span><span class="tag">&gt;</span><span class="pln">...</span><span class="tag">&lt;/a&gt;</span><span class="pln">
</span><span class="tag">&lt;a</span><span class="pln"> </span><span class="atn">href</span><span class="pun">=</span><span class="atv">"http://ya.ru"</span><span class="tag">&gt;</span><span class="pln">...</span><span class="tag">&lt;/a&gt;</span><span class="pln">

</span><span class="tag">&lt;script&gt;</span><span class="pln">
  </span><span class="com">// document.body.children يمكن تطبيقها على أيّة مجموعة مكان </span><span class="pln">
  </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let elem of document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">children</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">elem</span><span class="pun">.</span><span class="pln">matches</span><span class="pun">(</span><span class="str">'a[href$="zip"]'</span><span class="pun">))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      alert</span><span class="pun">(</span><span class="str">"The archive reference: "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> elem</span><span class="pun">.</span><span class="pln">href </span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" src="https://codepen.io/Hsoub/embed/preview/KKgOdYV?height=265&amp;theme-id=light&amp;default-tab=html,result" style="width: 100%;" title="JS-p2-04-searching-elements-dom-ex05">See the Pen JS-p2-04-searching-elements-dom-ex05 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<h2>
	closest
</h2>

<p>
	يتمثّل <em>أسلاف</em> (ancestors) عنصر ما في أبيه، وأب أبيه، وهكذا. يشكّل جميع اﻷسلاف معًا سلسلة الآباء التي تبتدئ من العنصر وتنتهي عند القمّة.
</p>

<p>
	يبحث تابع <code>(elem.closest(css</code> عن أقرب سلفٍ ينطبق عليه محدّد CSS. يشمل البحثُ العنصرَ <code>elem</code> نفسَه.
</p>

<p>
	بعبارة أخرى، ينطلق التابع <code>closest</code> صعودًا من العنصر المراد ويفحص كلّا من الآباء. فإذا طابق أحد اﻷسلاف المُحدِّد يتوقّف البحث، ويعيدُ السلفَ المطابق.
</p>

<p>
	على سبيل المثال:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1573_19" style="">
<span class="tag">&lt;h1&gt;</span><span class="pln">Contents</span><span class="tag">&lt;/h1&gt;</span><span class="pln">

</span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"contents"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;ul</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"book"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;li</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"chapter"</span><span class="tag">&gt;</span><span class="pln">Chapter 1</span><span class="tag">&lt;/li&gt;</span><span class="pln">
    </span><span class="tag">&lt;li</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"chapter"</span><span class="tag">&gt;</span><span class="pln">Chapter 1</span><span class="tag">&lt;/li&gt;</span><span class="pln">
  </span><span class="tag">&lt;/ul&gt;</span><span class="pln">
</span><span class="tag">&lt;/div&gt;</span><span class="pln">

</span><span class="tag">&lt;script&gt;</span><span class="pln">
  let chapter </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">'.chapter'</span><span class="pun">);</span><span class="pln"> </span><span class="com">// LI</span><span class="pln">

  alert</span><span class="pun">(</span><span class="pln">chapter</span><span class="pun">.</span><span class="pln">closest</span><span class="pun">(</span><span class="str">'.book'</span><span class="pun">));</span><span class="pln"> </span><span class="com">// UL</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln">chapter</span><span class="pun">.</span><span class="pln">closest</span><span class="pun">(</span><span class="str">'.contents'</span><span class="pun">));</span><span class="pln"> </span><span class="com">// DIV</span><span class="pln">

  alert</span><span class="pun">(</span><span class="pln">chapter</span><span class="pun">.</span><span class="pln">closest</span><span class="pun">(</span><span class="str">'h1'</span><span class="pun">));</span><span class="pln"> </span><span class="com">// (ليس من اﻷسلاف h1 ﻷن) null</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" src="https://codepen.io/Hsoub/embed/preview/LYRwpvd?height=265&amp;theme-id=light&amp;default-tab=html,result" style="width: 100%;" title="JS-p2-04-searching-elements-dom-ex06">See the Pen JS-p2-04-searching-elements-dom-ex06 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<h2>
	*getElementsBy
</h2>

<p>
	هناك أيضا توابع أخرى للبحث عن العقد حسب الوسم (tag) والصنف (class) وغيرها.
</p>

<p>
	تُعدّ هذه التوابع غالبًا من الماضي، إذ أنّ <code>querySelector</code> أقوى وأقصر في الكتابة.
</p>

<p>
	إذًا سنذكرها هنا من باب التمام، كما أنّه لا يزال من الممكن إيجادها في النصوص البرمجيّة القديمة.
</p>

<ul>
<li>
		يبحث <code>(elem.getElementsByTagName(tag</code> عن العناصر التي لها نفس الوسم المُراد ويعيدهم جميعا على شكل مجموعة. يمكن للمعامل <code>tag</code> أن يكون نجمة أيضا <code>"*"</code> ليشمل "جميع الوسوم".
	</li>
	<li>
		يعيد <code>(elem.getElementsByClassName(className</code> العناصر التي لها نفس صنف CSS المراد.
	</li>
	<li>
		يعيد <code>(document.getElementsByName(name</code> كل العناصر التي في المستند التي لها نفس السمة <code>name</code>. يندر استعمال هذا التابع.
	</li>
</ul>
<p>
	على سبيل المثال:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1573_21" style="">
<span class="com">// التي في المستند div حصّل جميع وسوم</span><span class="pln">
let divs </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">getElementsByTagName</span><span class="pun">(</span><span class="str">'div'</span><span class="pun">);</span></pre>

<p>
	لنجد جميع وسوم <code>input</code> التي في المستند:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1573_23" style="">
<span class="tag">&lt;table</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"table"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;tr&gt;</span><span class="pln">
    </span><span class="tag">&lt;td&gt;</span><span class="pln">Your age:</span><span class="tag">&lt;/td&gt;</span><span class="pln">

    </span><span class="tag">&lt;td&gt;</span><span class="pln">
      </span><span class="tag">&lt;label&gt;</span><span class="pln">
        </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"radio"</span><span class="pln"> </span><span class="atn">name</span><span class="pun">=</span><span class="atv">"age"</span><span class="pln"> </span><span class="atn">value</span><span class="pun">=</span><span class="atv">"young"</span><span class="pln"> </span><span class="atn">checked</span><span class="tag">&gt;</span><span class="pln"> less than 18
      </span><span class="tag">&lt;/label&gt;</span><span class="pln">
      </span><span class="tag">&lt;label&gt;</span><span class="pln">
        </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"radio"</span><span class="pln"> </span><span class="atn">name</span><span class="pun">=</span><span class="atv">"age"</span><span class="pln"> </span><span class="atn">value</span><span class="pun">=</span><span class="atv">"mature"</span><span class="tag">&gt;</span><span class="pln"> from 18 to 50
      </span><span class="tag">&lt;/label&gt;</span><span class="pln">
      </span><span class="tag">&lt;label&gt;</span><span class="pln">
        </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"radio"</span><span class="pln"> </span><span class="atn">name</span><span class="pun">=</span><span class="atv">"age"</span><span class="pln"> </span><span class="atn">value</span><span class="pun">=</span><span class="atv">"senior"</span><span class="tag">&gt;</span><span class="pln"> more than 60
      </span><span class="tag">&lt;/label&gt;</span><span class="pln">
    </span><span class="tag">&lt;/td&gt;</span><span class="pln">
  </span><span class="tag">&lt;/tr&gt;</span><span class="pln">
</span><span class="tag">&lt;/table&gt;</span><span class="pln">

</span><span class="tag">&lt;script&gt;</span><span class="pln">
  let inputs </span><span class="pun">=</span><span class="pln"> table</span><span class="pun">.</span><span class="pln">getElementsByTagName</span><span class="pun">(</span><span class="str">'input'</span><span class="pun">);</span><span class="pln">

  </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let input of inputs</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    alert</span><span class="pun">(</span><span class="pln"> input</span><span class="pun">.</span><span class="pln">value </span><span class="pun">+</span><span class="pln"> </span><span class="str">': '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> input</span><span class="pun">.</span><span class="pln">checked </span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" src="https://codepen.io/Hsoub/embed/preview/MWjNadb?height=265&amp;theme-id=light&amp;default-tab=html,result" style="width: 100%;" title="JS-p2-04-searching-elements-dom-ex07">See the Pen JS-p2-04-searching-elements-dom-ex07 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<hr>
<p>
	<strong>لا تنسَ حرف <code>"s"</code> للجمع!</strong>
</p>

<p>
	ينسى المطوّرون المبتدئون أحيانا الحرف <code>"s"</code>، فيعمدون إلى مناداة <code>getElementByTagName</code> بدل <code>getElement&lt;b&gt;s&lt;/b&gt;ByTagName</code>.
</p>

<p>
	يخلو <code>getElementByTagName</code> من الحرف <code>"s"</code> ﻷنّه يعيد عنصرا وحيدا. لكنّ <code>getElement&lt;b&gt;s&lt;/b&gt;ByTagName</code> يعيد مجموعة من العناصر، لهذا فإنّ بداخله <code>"s"</code>.
</p>

<hr>
<hr>
<p>
	<strong>يعيد التابع مجموعة، وليس عنصرًا!</strong>
</p>

<p>
	من الأخطاء الشائعة لدى المبتدئين أيضا هو كتابة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1573_25" style="">
<span class="com">// لا تعمل</span><span class="pln">
document</span><span class="pun">.</span><span class="pln">getElementsByTagName</span><span class="pun">(</span><span class="str">'input'</span><span class="pun">).</span><span class="pln">value </span><span class="pun">=</span><span class="pln"> </span><span class="lit">5</span><span class="pun">;</span></pre>

<p>
	لن يعمل ذلك، ﻷنّه يحاول إسناد القيمة إلى <em>مجموعة</em>ٍ من المُدخلات بدل إسنادها إلى العناصر التي تحتويها.
</p>

<p>
	يجب علينا إمّا التكرار على المجموعة أو تحصيل عنصر بواسطة معامله ثمّ إسناد القيمة له هكذا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1573_27" style="">
<span class="com">// (ًيُفترض أن تعمل (إذا كانت هناك مُدخلات</span><span class="pln">
document</span><span class="pun">.</span><span class="pln">getElementsByTagName</span><span class="pun">(</span><span class="str">'input'</span><span class="pun">)[</span><span class="lit">0</span><span class="pun">].</span><span class="pln">value </span><span class="pun">=</span><span class="pln"> </span><span class="lit">5</span><span class="pun">;</span></pre>

<hr>
<p>
	للبحث عن العناصر ذات الصنف <code>article.</code>:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1573_29" style="">
<span class="tag">&lt;form</span><span class="pln"> </span><span class="atn">name</span><span class="pun">=</span><span class="atv">"my-form"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"article"</span><span class="tag">&gt;</span><span class="pln">Article</span><span class="tag">&lt;/div&gt;</span><span class="pln">
  </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"long article"</span><span class="tag">&gt;</span><span class="pln">Long article</span><span class="tag">&lt;/div&gt;</span><span class="pln">
</span><span class="tag">&lt;/form&gt;</span><span class="pln">

</span><span class="tag">&lt;script&gt;</span><span class="pln">
  </span><span class="com">// name أوجد حسب السمة</span><span class="pln">
  let form </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">getElementsByName</span><span class="pun">(</span><span class="str">'my-form'</span><span class="pun">)[</span><span class="lit">0</span><span class="pun">];</span><span class="pln">

  </span><span class="com">// أوجد حسب الصنف داخل النموذج</span><span class="pln">
  let articles </span><span class="pun">=</span><span class="pln"> form</span><span class="pun">.</span><span class="pln">getElementsByClassName</span><span class="pun">(</span><span class="str">'article'</span><span class="pun">);</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln">articles</span><span class="pun">.</span><span class="pln">length</span><span class="pun">);</span><span class="pln"> </span><span class="com">// 2 - "article" وجدنا عنصران لهما الصنف</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" src="https://codepen.io/Hsoub/embed/preview/gOwVaJy?height=265&amp;theme-id=light&amp;default-tab=html,result" style="width: 100%;" title="JS-p2-04-searching-elements-dom-ex08">See the Pen JS-p2-04-searching-elements-dom-ex08 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<h2>
	المجموعات الحية
</h2>

<p>
	تُعيد جميع التوابع <code>"*getElementsBy"</code> مجموعة <em>حيّة</em> (live). تعكس هذه المجموعات الوضع الحاليّ الذي عليه المستند و "تُحدَّث تلقائيًّا" كلّما تغيّر.
</p>

<p>
	في المثال أدناه نصّان برمجيّان:
</p>

<ol>
<li>
		يُنشئ اﻷوّل مرجعًا إلى مجموعة العناصر <code>&lt;div&gt;</code>؛ طول المجموعة عندها هو <code>1</code>.
	</li>
	<li>
		يُنفَّذ النصّ الثاني بعدما يقابل المتصفّح عنصر <code>&lt;div&gt;</code> آخر، ويكون طول المجموعة حينها هو <code>2</code>.
	</li>
</ol>
<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1573_31" style="">
<span class="tag">&lt;div&gt;</span><span class="pln">First div</span><span class="tag">&lt;/div&gt;</span><span class="pln">

</span><span class="tag">&lt;script&gt;</span><span class="pln">
  let divs </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">getElementsByTagName</span><span class="pun">(</span><span class="str">'div'</span><span class="pun">);</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln">divs</span><span class="pun">.</span><span class="pln">length</span><span class="pun">);</span><span class="pln"> </span><span class="com">// 1</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span><span class="pln">

</span><span class="tag">&lt;div&gt;</span><span class="pln">Second div</span><span class="tag">&lt;/div&gt;</span><span class="pln">

</span><span class="tag">&lt;script&gt;</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln">divs</span><span class="pun">.</span><span class="pln">length</span><span class="pun">);</span><span class="pln"> </span><span class="com">// 2</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" src="https://codepen.io/Hsoub/embed/preview/WNGVQqv?height=265&amp;theme-id=light&amp;default-tab=html,result" style="width: 100%;" title="JS-p2-04-searching-elements-dom-ex09">See the Pen JS-p2-04-searching-elements-dom-ex09 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	في المقابل، يعيد <code>querySelectorAll</code> مجموعة <em>ساكنة</em> (static)، كأنّها مصفوفة ثابتة من العناصر.
</p>

<p>
	إذا طبقناه في المثال أعلاه، فسيُخرج كلا النصّان <code>1</code>:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1573_33" style="">
<span class="tag">&lt;div&gt;</span><span class="pln">First div</span><span class="tag">&lt;/div&gt;</span><span class="pln">

</span><span class="tag">&lt;script&gt;</span><span class="pln">
  let divs </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">querySelectorAll</span><span class="pun">(</span><span class="str">'div'</span><span class="pun">);</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln">divs</span><span class="pun">.</span><span class="pln">length</span><span class="pun">);</span><span class="pln"> </span><span class="com">// 1</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span><span class="pln">

</span><span class="tag">&lt;div&gt;</span><span class="pln">Second div</span><span class="tag">&lt;/div&gt;</span><span class="pln">

</span><span class="tag">&lt;script&gt;</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln">divs</span><span class="pun">.</span><span class="pln">length</span><span class="pun">);</span><span class="pln"> </span><span class="com">// 1</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" src="https://codepen.io/Hsoub/embed/preview/LYRwpKm?height=265&amp;theme-id=light&amp;default-tab=html,result" style="width: 100%;" title="JS-p2-04-searching-elements-dom-ex10">See the Pen JS-p2-04-searching-elements-dom-ex10 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	يمكننا الآن رؤية الفرق بوضوح. لم تزدد المجموعة الساكنة بظهور عنصر <code>&lt;div&gt;</code> جديد في المستند.
</p>

<h2>
	الملخص
</h2>

<p>
	هناك 6 توابع رئيسيّة للبحث عن العقد في DOM:
</p>

<table>
<thead><tr>
<th>
				التابع
			</th>
			<th>
				يبحث بواسطة ...
			</th>
			<th>
				يمكن مناداته على عنصر؟
			</th>
			<th>
				حيّة؟
			</th>
		</tr></thead>
<tbody>
<tr>
<td>
				<code>querySelector</code>
			</td>
			<td>
				محدّد CSS
			</td>
			<td>
				✔
			</td>
			<td>
				-
			</td>
		</tr>
<tr>
<td>
				<code>querySelectorAll</code>
			</td>
			<td>
				محدّد CSS
			</td>
			<td>
				✔
			</td>
			<td>
				-
			</td>
		</tr>
<tr>
<td>
				<code>getElementById</code>
			</td>
			<td>
				<code>id</code>
			</td>
			<td>
				-
			</td>
			<td>
				-
			</td>
		</tr>
<tr>
<td>
				<code>getElementsByName</code>
			</td>
			<td>
				<code>name</code>
			</td>
			<td>
				-
			</td>
			<td>
				✔
			</td>
		</tr>
<tr>
<td>
				<code>getElementsByTagName</code>
			</td>
			<td>
				الوسم أو <code>'*'</code>
			</td>
			<td>
				✔
			</td>
			<td>
				✔
			</td>
		</tr>
<tr>
<td>
				<code>getElementsByClassName</code>
			</td>
			<td>
				الصنف
			</td>
			<td>
				✔
			</td>
			<td>
				✔
			</td>
		</tr>
</tbody>
</table>
<style type="text/css">
table {
    width: 100%;
}

thead {
    vertical-align: middle;

    text-align: center;} 

td, th {
    border: 1px solid #dddddd;
    text-align: right;
    padding: 8px;
    text-align: inherit;

}
tr:nth-child(even) {
    background-color: #dddddd;
}</style>
<p>
	تُعدّ <code>querySelector</code> و <code>querySelectorAll</code> أكثرها استخداما على الإطلاق، لكن قد تُفيد <code>*getElementBy</code> أحيانا أو قد توجد في النصوص البرمجيّة القديمة.
</p>

<p>
	عدا ذلك:
</p>

<ul>
<li>
		هناك <code>(elem.matches(css</code> للتحقّق من أنّ العنصر <code>elem</code> مطابق لمحدّد CSS المراد.
	</li>
	<li>
		هناك <code>(elem.closest(css</code> للبحث عن أقرب سلفٍ مطابق لمحدّد CSS المراد. يشمل البحثُ العنصرَ نفسه.
	</li>
</ul>
<p>
	ولنضف هنا تابعا آخر للتحقّق من العلاقة ابن-أب، إذ قد تفيد أحيانا:
</p>

<ul>
<li>
		يعيد <code>(elemA.contains(elemB</code> القيمة <code>true</code> إذا كان <code>elemB</code> داخلا تحت <code>elemA</code> (أي عنصرا سليلا لـ <code>elemA</code>) أو إذا كان <code>elemA==elemB</code>.
	</li>
</ul>
<h2>
	التمارين
</h2>

<h3>
	البحث عن العناصر
</h3>

<p>
	اﻷهميّة: 4
</p>

<p>
	إليك مستندًا يحتوي على جدول ونموذج.
</p>

<p>
	كيف يمكن إيجاد؟ …
</p>

<ol>
<li>
		الجدول الذي له <code>"id="age-table</code>.
	</li>
	<li>
		جميع العناصر <code>label</code> بداخل ذلك الجدول (من المفترض أن تكون هناك 3 منها).
	</li>
	<li>
		أوّل <code>td</code> في ذلك الجدول (التي فيها الكلمة "Age").
	</li>
	<li>
		النموذج <code>form</code> الذي له <code>"name="search</code>.
	</li>
	<li>
		أوّل <code>input</code> في ذلك النموذج.
	</li>
	<li>
		آخر <code>input</code> في ذلك النموذج
	</li>
</ol>
<p>
	افتح <a href="table.html" rel="">table.html</a> في نافذة مستقلة واستعمل أدوات المتصفّح لذلك.
</p>

<h3>
	الحل
</h3>

<p>
	هناك عدّة طرق لفعل ذلك.
</p>

<p>
	هذه إحداها:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1573_35" style="">
<span class="com">// id="age-table" الجدول الذي له</span><span class="pln">
let table </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">'age-table'</span><span class="pun">)</span><span class="pln">

</span><span class="com">// بداخل ذلك الجدول label جميع العناصر</span><span class="pln">
table</span><span class="pun">.</span><span class="pln">getElementsByTagName</span><span class="pun">(</span><span class="str">'label'</span><span class="pun">)</span><span class="pln">
</span><span class="com">// أو</span><span class="pln">
document</span><span class="pun">.</span><span class="pln">querySelectorAll</span><span class="pun">(</span><span class="str">'#age-table label'</span><span class="pun">)</span><span class="pln">

</span><span class="com">//  ("Age" في ذلك الجدول (التي فيها الكلمة td أوّل </span><span class="pln">
table</span><span class="pun">.</span><span class="pln">rows</span><span class="pun">[</span><span class="lit">0</span><span class="pun">].</span><span class="pln">cells</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]</span><span class="pln">
</span><span class="com">// أو</span><span class="pln">
table</span><span class="pun">.</span><span class="pln">getElementsByTagName</span><span class="pun">(</span><span class="str">'td'</span><span class="pun">)[</span><span class="lit">0</span><span class="pun">]</span><span class="pln">
</span><span class="com">// أو</span><span class="pln">
table</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">'td'</span><span class="pun">)</span><span class="pln">

</span><span class="com">// name="search" النموذج الذي له</span><span class="pln">
</span><span class="com">//  name="search" على افتراض أنّ هناك عنصرا واحدا في المستند له</span><span class="pln">
let form </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">getElementsByName</span><span class="pun">(</span><span class="str">'search'</span><span class="pun">)[</span><span class="lit">0</span><span class="pun">]</span><span class="pln">
</span><span class="com">// خصّيصا form ،أو</span><span class="pln">
document</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">'form[name="search"]'</span><span class="pun">)</span><span class="pln">

</span><span class="com">// في ذلك النموذج input أوّل</span><span class="pln">
form</span><span class="pun">.</span><span class="pln">getElementsByTagName</span><span class="pun">(</span><span class="str">'input'</span><span class="pun">)[</span><span class="lit">0</span><span class="pun">]</span><span class="pln">
</span><span class="com">// أو</span><span class="pln">
form</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">'input'</span><span class="pun">)</span><span class="pln">


</span><span class="com">// في ذلك النموذج input آخر</span><span class="pln">
let inputs </span><span class="pun">=</span><span class="pln"> form</span><span class="pun">.</span><span class="pln">querySelectorAll</span><span class="pun">(</span><span class="str">'input'</span><span class="pun">)</span><span class="pln"> </span><span class="com">// inputs أوجد جميع الـ </span><span class="pln">
inputs</span><span class="pun">[</span><span class="pln">inputs</span><span class="pun">.</span><span class="pln">length</span><span class="pun">-</span><span class="lit">1</span><span class="pun">]</span><span class="pln"> </span><span class="com">// اختر آخرها</span></pre>

<hr>
<p>
	ترجمة وبتصرف لمقال <a href="https://javascript.info/searching-elements-dom#querySelectorAll" rel="external nofollow">*Searching: getElement*, querySelector</a> من كتاب <a href="https://javascript.info/" rel="external nofollow">The Modern JavaScript Tutorial</a>
</p>
]]></description><guid isPermaLink="false">1106</guid><pubDate>Sat, 23 Jan 2021 13:00:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x62A;&#x646;&#x642;&#x644; &#x641;&#x64A; &#x634;&#x62C;&#x631;&#x629; DOM &#x639;&#x628;&#x631; &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A;</title><link>https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%AA%D9%86%D9%82%D9%84-%D9%81%D9%8A-%D8%B4%D8%AC%D8%B1%D8%A9-dom-%D8%B9%D8%A8%D8%B1-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r1105/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_01/600fdd2c2cc67_---dom.png.53aaec7286d0b0ae221088dcd40dedc7.png" /></p>

<p>
	يُمكّننا DOM من فعل أيّ شيء بالعناصر وما تحتويه، لكن نحتاج أوّلا إلى أن نصل إلى الكائن المحدّد من DOM.
</p>

<p>
	تبدأ جميع العمليّات على DOM بالكائن <code>document</code>. فهو "نقطة الدخول" الرئيسيّة إلى DOM، ويمكن من خلاله الوصول إلى جميع العقد.
</p>

<p>
	تمثّل الصورة التالية الروابط التي يمكن من خلالها التنقّل بين العقد في DOM.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="56440" href="https://academy.hsoub.com/uploads/monthly_2021_01/dom-links.png.793a3f94af5b8868c57bebeb283c9189.png" rel=""><img alt="dom-links.png" class="ipsImage ipsImage_thumbnailed" data-fileid="56440" data-unique="5z2t5e9uo" src="https://academy.hsoub.com/uploads/monthly_2021_01/dom-links.png.793a3f94af5b8868c57bebeb283c9189.png"></a>
</p>

<p>
	لنتناولها بمزيدٍ من التفصيل.
</p>

<h2>
	في اﻷعلى: documentElement و body
</h2>

<p>
	تُتاح العقد العلويّة للشجرة مباشرةً على شكل خاصّيّات لكائن <code>document</code>:
</p>

<ul>
<li>
		<p>
			<code>&lt;html&gt;</code> =‏ <code>document.documentElement</code>: تكون العقدة التي في قمّة الشجرة <code>document.documentElement</code> ، وهي عقدة DOM التي تمثّل وسم <code>&lt;html&gt;</code>.
		</p>
	</li>
	<li>
		<p>
			<code>&lt;body&gt;</code> =‏ <code>document.body</code>: من العقد التي يكثر استعمالاها أيضا عنصر <code>&lt;body&gt;</code> الذي يمثّله كائن <code>document.body</code>
		</p>
	</li>
	<li>
		<p>
			<code>&lt;head&gt;</code> =‏ <code>document.head</code>: يكون وسم <code>&lt;head&gt;</code> متاحا كـ <code>document.head</code>.
		</p>
	</li>
</ul>
<hr>
<p>
	<strong>هناك خدعة: قد يكون <code>document.body</code> عديم القيمة (أي <code>null</code>)</strong>
</p>

<p>
	لا يستطيع السكربت الوصول إلى عنصر غير موجود حال تنفيذه.
</p>

<p>
	فمثلا، إذا كان السكربت بداخل <code>&lt;head&gt;</code> فإنّ <code>document.body</code> غير متاح له، ﻷن المتصفّح لم يبلغ موضعه بعد حتى يقرأه.
</p>

<p>
	ففي المثال أدناه، يعرض لنا الـ <code>alert</code> اﻷوّل القيمة العدميّة <code>null</code>:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_4824_7" style="">
<span class="tag">&lt;html&gt;</span><span class="pln">

</span><span class="tag">&lt;head&gt;</span><span class="pln">
  </span><span class="tag">&lt;script&gt;</span><span class="pln">
    alert</span><span class="pun">(</span><span class="pln"> </span><span class="str">"From HEAD: "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">body </span><span class="pun">);</span><span class="pln"> </span><span class="com">// بعد &lt;body&gt; فليس هناك ،null</span><span class="pln">
  </span><span class="tag">&lt;/script&gt;</span><span class="pln">
</span><span class="tag">&lt;/head&gt;</span><span class="pln">

</span><span class="tag">&lt;body&gt;</span><span class="pln">

  </span><span class="tag">&lt;script&gt;</span><span class="pln">
    alert</span><span class="pun">(</span><span class="pln"> </span><span class="str">"From BODY: "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">body </span><span class="pun">);</span><span class="pln"> </span><span class="com">// فهو الآن موجود ،HTMLBodyElement </span><span class="pln">
  </span><span class="tag">&lt;/script&gt;</span><span class="pln">

</span><span class="tag">&lt;/body&gt;</span><span class="pln">
</span><span class="tag">&lt;/html&gt;</span></pre>

<hr>
<hr>
<p>
	<strong>في عالم DOM، تعني <code>null</code> أنّه "غير موجود"</strong>
</p>

<p>
	في DOM، تعني القيمة <code>null</code> أنّه "غير موجود" أو "لا وجود لهذه العقدة".
</p>

<hr>
<h2>
	اﻷبناء: lastChild ، firstChild ، childNodes
</h2>

<p>
	هناك مصطلحان سنستعملهما من الآن فصاعد:
</p>

<ul>
<li>
		العقد اﻷبناء (أو اﻷبناء باختصار) -- العناصر الذين هم أبناء مباشرون، أو بعبارة أخرى، هي العناصر المتفرعة عن العنصر المراد مباشرة. على سبيل المثال، العنصران <code>&lt;head&gt;</code> و <code>&lt;body&gt;</code> هما أبناء لعنصر <code>&lt;html&gt;</code>.
	</li>
	<li>
		العقد السليلة (descendants) -- جميع العناصر المتفرعة عن العنصر المراد، بما ذلك أبناؤه وأبناء أبنائه، إلى آخر ذلك.
	</li>
</ul>
<p>
	فمثلا هنا، للعنصر <code>&lt;body&gt;</code> اﻷبناء <code>&lt;div&gt;</code> و <code>&lt;ul&gt;</code> (وبعض العقد المتكوّنة من فراغات):
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_4824_9" style="">
<span class="tag">&lt;html&gt;</span><span class="pln">
</span><span class="tag">&lt;body&gt;</span><span class="pln">
  </span><span class="tag">&lt;div&gt;</span><span class="pln">Begin</span><span class="tag">&lt;/div&gt;</span><span class="pln">

  </span><span class="tag">&lt;ul&gt;</span><span class="pln">
    </span><span class="tag">&lt;li&gt;</span><span class="pln">
      </span><span class="tag">&lt;b&gt;</span><span class="pln">Information</span><span class="tag">&lt;/b&gt;</span><span class="pln">
    </span><span class="tag">&lt;/li&gt;</span><span class="pln">
  </span><span class="tag">&lt;/ul&gt;</span><span class="pln">
</span><span class="tag">&lt;/body&gt;</span><span class="pln">
</span><span class="tag">&lt;/html&gt;</span></pre>

<p>
	… وأمّا العقد السليلة لـ <code>&lt;body&gt;</code> فليست أبناءه المباشرين <code>&lt;div&gt;</code> و <code>&lt;ul&gt;</code> فحسب، بل تشمل كلّ العقد المتفرّعة منه، مثل <code>&lt;li&gt;</code> (الذي هو ابنً لـ <code>&lt;ul&gt;</code>) و <code>&lt;b&gt;</code> (الذي هو ابنٌ لـ <code>&lt;div&gt;</code>) -- الشجرة الفرعيّة بأكملها.
</p>

<p>
	<strong>تضمّ المجموعة <code>childNodes</code> كل العقد اﻷبناء، بما في ذلك العقد النصيّة.</strong>
</p>

<p>
	يقوم المثال أدناه بعرض أبناء <code>document.body</code>:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_4824_11" style="">
<span class="tag">&lt;html&gt;</span><span class="pln">
</span><span class="tag">&lt;body&gt;</span><span class="pln">
  </span><span class="tag">&lt;div&gt;</span><span class="pln">Begin</span><span class="tag">&lt;/div&gt;</span><span class="pln">

  </span><span class="tag">&lt;ul&gt;</span><span class="pln">
    </span><span class="tag">&lt;li&gt;</span><span class="pln">Information</span><span class="tag">&lt;/li&gt;</span><span class="pln">
  </span><span class="tag">&lt;/ul&gt;</span><span class="pln">

  </span><span class="tag">&lt;div&gt;</span><span class="pln">End</span><span class="tag">&lt;/div&gt;</span><span class="pln">

  </span><span class="tag">&lt;script&gt;</span><span class="pln">
    </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">childNodes</span><span class="pun">.</span><span class="pln">length</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      alert</span><span class="pun">(</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">childNodes</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// Text, DIV, Text, UL, ..., SCRIPT</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="tag">&lt;/script&gt;</span><span class="pln">
  ...المزيد من اﻷشياء...
</span><span class="tag">&lt;/body&gt;</span><span class="pln">
</span><span class="tag">&lt;/html&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-03-dom-navigation-ex01" src="https://codepen.io/Hsoub/embed/preview/rNMXVQX?height=265&amp;theme-id=light&amp;default-tab=html,result">See the Pen JS-p2-03-dom-navigation-ex01 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	يُرجى الانتباه ﻷمر دقيق هنا. لو أجرينا المثال السابق، سيكون <code>&lt;script&gt;</code> هو آخر العناصر التي تُعرض. في حقيقة اﻷمر، لاتزال هناك المزيد من اﻷشياء في المستند، لكن السكربت لم يرها، ﻷنّه حال تنفيذه، لم يكن المتصفّح قد اطّلع عليها بعد.
</p>

<p>
	<strong>تُمكّن الخاصّيات <code>firstChild</code> و <code>lastChild</code> الوصول بسهولة إلى أوّل اﻷبناء وآخرهم.</strong>
</p>

<p>
	هي فقط بمثابة اختصارات. إذا كان للعنصر <code>elem</code> عقدً أبناء، فإنّ العبارات التالية دائما صحيحة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4824_15" style="">
<span class="pln">elem</span><span class="pun">.</span><span class="pln">childNodes</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]</span><span class="pln"> </span><span class="pun">===</span><span class="pln"> elem</span><span class="pun">.</span><span class="pln">firstChild
elem</span><span class="pun">.</span><span class="pln">childNodes</span><span class="pun">[</span><span class="pln">elem</span><span class="pun">.</span><span class="pln">childNodes</span><span class="pun">.</span><span class="pln">length </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pun">]</span><span class="pln"> </span><span class="pun">===</span><span class="pln"> elem</span><span class="pun">.</span><span class="pln">lastChild</span></pre>

<p>
	هناك أيضا دالّة خاصّة <code>()elem.hasChildNodes</code> للتحقّق من أنّ له أبناءً.
</p>

<h3>
	مجموعات DOM
</h3>

<p>
	كما نلاحظ، تبدو <code>childNode</code> وكأنّها مصفوفة (array)، لكنّ الحقيقة أنّها ليست كذلك، بل هي باﻷحرى <em>مجموعة</em> (collection) -- كائن خاصّ شبيهً بالمصفوفة وقابل للتكرار عليه (iterable).
</p>

<p>
	ينجم عن هذا اﻷمر أثران مهمّان:
</p>

<ol>
<li>
		يمكننا استعمال <code>for..of</code> للتكرار عليه:
	</li>
</ol>
<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4824_17" style="">
<span class="pln">     </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let node of document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">childNodes</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
       alert</span><span class="pun">(</span><span class="pln">node</span><span class="pun">);</span><span class="pln"> </span><span class="com">//  يعرض هذا جميع العقد التي في المجموعة</span><span class="pln">
     </span><span class="pun">}</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-03-dom-navigation-ex02" src="https://codepen.io/Hsoub/embed/preview/ExgqVyy?height=265&amp;theme-id=light&amp;default-tab=js,result">See the Pen JS-p2-03-dom-navigation-ex02 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	هذا ﻷنّه قابل للتكرار (أي أنّه يتيح خاصّيّة <code>Symbol.iterator</code> كما يلزم).
</p>

<ol start="2">
<li>
		لا يمكننا استعمال توابع المصفوفة معها، ﻷنّها ليست مصفوفة:
	</li>
</ol>
<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4824_19" style="">
<span class="pln">   alert</span><span class="pun">(</span><span class="pln">document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">childNodes</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">);</span><span class="pln"> </span><span class="com">//  (filter غير معرّف (ليس هناك تابع اسمه  </span></pre>

<p>
	الأمر اﻷوّل جيّد. كما أنّه لا بأس باﻷمر الثاني، ﻷنّه يمكننا استعمال <code>Array.from</code> ﻹنشاء مصفوفة "حقيقيّة" من المجموعة، إذا رغبنا في توابع المصفوفة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4824_21" style="">
<span class="pln">alert</span><span class="pun">(</span><span class="pln"> </span><span class="typ">Array</span><span class="pun">.</span><span class="pln">from</span><span class="pun">(</span><span class="pln">document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">childNodes</span><span class="pun">).</span><span class="pln">filter </span><span class="pun">);</span><span class="pln"> </span><span class="com">// function</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-03-dom-navigation-ex03" src="https://codepen.io/Hsoub/embed/preview/WNGVQxm?height=265&amp;theme-id=light&amp;default-tab=js,result">See the Pen JS-p2-03-dom-navigation-ex03 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<hr>
<p>
	<strong>مجموعات DOM هي للقراءة فقط</strong>
</p>

<p>
	مجموعات DOM، بل زد على ذلك، <em>جميع</em> خاصّيّات التنقّل التي ذكرناها في هذا المقال هي للقراءة فقط (read-only).
</p>

<p>
	فلا يمكن مثلا استبدال ابنٍ بشيء آخر بواسطة الإسناد <code>... = [childNodes[i</code>.
</p>

<p>
	يتطلب تغيير DOM توابع أخرى سنتناولها في المقال التالي.
</p>

<hr>
<hr>
<p>
	<strong>مجموعات DOM حيّة</strong>
</p>

<p>
	كلّ مجموعات DOM تقريبا، مع بعض الاستثناءات القليلة، هي <em>حيّة</em> (live). ما يعني ذلك أنّها تعكس الوضع الحاليّ لـ DOM.
</p>

<p>
	إذا احتفظنا بمرجع للمجموعة <code>elem.childNodes</code> ، وأضفنا أو أزلنا عقدا من DOM، فإنّها تظهر في المجموعة تلقائيّا.
</p>

<hr>
<hr>
<p>
	<strong>لا تستعمل <code>for..in</code> للتكرار على المجموعات</strong>
</p>

<p>
	رغم أنّ المجموعات تقبل التكرار بواسطة <code>for..in</code>، لكنّه يُفضّل عدم استعمالها لذلك.
</p>

<p>
	تمرّ <code>for..in</code> على جميع الخاصّيّات التي يمكن تعدادها (enumerable)، وللمجموعات بعض الخاصّيّات "الإضافيّة" التي يندر استعمالها ولا نودّ أن نحصل عليها:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_4824_23" style="">
<span class="tag">&lt;body&gt;</span><span class="pln">
</span><span class="tag">&lt;script&gt;</span><span class="pln">
  </span><span class="com">// وأكثر ،values ،item ،length ،1 ،0 سيعرض هذا كلّا من</span><span class="pln">
  </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let prop in document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">childNodes</span><span class="pun">)</span><span class="pln"> alert</span><span class="pun">(</span><span class="pln">prop</span><span class="pun">);</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span><span class="pln">
</span><span class="tag">&lt;/body&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-03-dom-navigation-ex04" src="https://codepen.io/Hsoub/embed/preview/yLamYVB?height=265&amp;theme-id=light&amp;default-tab=html,result">See the Pen JS-p2-03-dom-navigation-ex04 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<hr>
<h2>
	الإخوة واﻷب
</h2>

<p>
	<em>الإخوة</em> (siblings) هم عقدٌ أبناء لنفس الأب.
</p>

<p>
	فمثلا هنا، <code>&lt;head&gt;</code> و <code>&lt;body&gt;</code> هما أخوين:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_4824_25" style="">
<span class="tag">&lt;html&gt;</span><span class="pln">
  </span><span class="tag">&lt;head&gt;</span><span class="pln">...</span><span class="tag">&lt;/head&gt;&lt;body&gt;</span><span class="pln">...</span><span class="tag">&lt;/body&gt;</span><span class="pln">
</span><span class="tag">&lt;/html&gt;</span></pre>

<ul>
<li>
		يُقال عن <code>&lt;body&gt;</code> أنّه اﻷخ "التالي" أو "اﻷيمن" لـ <code>&lt;head&gt;</code>.
	</li>
	<li>
		يُقال عن <code>&lt;head&gt;</code> أنّه اﻷخ "السابق" أو "الأيسر" لـ <code>&lt;body&gt;</code> .
	</li>
</ul>
<p>
	يكون اﻷخ التالي مُتاحا في الخاصّيّة <code>nextSibling</code>، والأخ السابق في الخاصّيّة <code>previousSibling</code>. بينما يكون اﻷب مُتاحا في الخاصّيّة <code>parentNode</code>.
</p>

<p>
	على سبيل المثال:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4824_27" style="">
<span class="com">// &lt;html&gt; هو &lt;body&gt; أب </span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">parentNode </span><span class="pun">===</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">documentElement </span><span class="pun">);</span><span class="pln"> </span><span class="com">// صحيح</span><span class="pln">

</span><span class="com">// &lt;body&gt; يأتي&lt;head&gt; بعد</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">head</span><span class="pun">.</span><span class="pln">nextSibling </span><span class="pun">);</span><span class="pln"> </span><span class="com">// HTMLBodyElement</span><span class="pln">

</span><span class="com">// &lt;head&gt; يكون &lt;body&gt; قبل</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">previousSibling </span><span class="pun">);</span><span class="pln"> </span><span class="com">// HTMLHeadElement</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-03-dom-navigation-ex05" src="https://codepen.io/Hsoub/embed/preview/QWKejGR?height=265&amp;theme-id=light&amp;default-tab=js,result">See the Pen JS-p2-03-dom-navigation-ex05 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<h2>
	التنقّل بين العناصر فقط
</h2>

<p>
	تربط خاصّيّات التنقّل المذكورة أعلاه <em>بجميع</em> أنواع العقد. فيمكننا مثلا من خلال <code>childNodes</code> الاطلاع على كلٍّ من العقد النصّيّة والعقد العنصريّة، بل وحتى العقد التعليقيّة إن وُجدت.
</p>

<p>
	لكنّنا في العديد من المهامّ لا نرغب في العقد النصّيّة والتعليقيّة. بل نرغب في معالجة العقد العنصريّة التي تمثّل الوسوم وتشكّل بنية الصفحة.
</p>

<p>
	لنرى إذًا بعض روابط التنقّل اﻷخرى التي تأخذ في الحسبان العقد النصيّة فقط:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="56439" href="https://academy.hsoub.com/uploads/monthly_2021_01/dom-links-elements.png.b8640b7164325959157f803bc65bac4f.png" rel=""><img alt="dom-links-elements.png" class="ipsImage ipsImage_thumbnailed" data-fileid="56439" data-unique="tjtd03i83" src="https://academy.hsoub.com/uploads/monthly_2021_01/dom-links-elements.png.b8640b7164325959157f803bc65bac4f.png"></a>
</p>

<p>
	هذه الروابط مماثلة لتلك المذكورة أعلاه، مع إضافة كلمة <code>Element</code> في وسطها:
</p>

<ul>
<li>
		<code>children</code> -- الأبناء الذين هم عقد عنصريّة فقط.
	</li>
	<li>
		<code>firstElementChild</code> و <code>lastElementChild</code> -- أوّل اﻷبناء وآخرهم من العقد العنصريّة.
	</li>
	<li>
		<code>previousElementSibling</code> و <code>nextElementSibling</code> -- العناصر المتجاورة.
	</li>
	<li>
		<code>parentElement</code> -- العنصر اﻷب.
	</li>
</ul>
<hr>
<p>
	<strong>ما الداعي إلى <code>parentElement</code> ؟ أيمكن للأب <em>ألّا</em> يكون عنصرا؟</strong>
</p>

<p>
	تُعيد خاصّيّة <code>parentElement</code> "العنصر" اﻷب، بينما تُعيد <code>parentNode</code> "أيّ عقدةٍ" أب. هاتان الخاصّيّتان متشابهتان في العادة: كلتاهما تُحصّل اﻷب.
</p>

<p>
	لكن هناك استثناءً وحيدا مع <code>document.documentElement</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4824_29" style="">
<span class="pln">alert</span><span class="pun">(</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">documentElement</span><span class="pun">.</span><span class="pln">parentNode </span><span class="pun">);</span><span class="pln"> </span><span class="com">// document</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">documentElement</span><span class="pun">.</span><span class="pln">parentElement </span><span class="pun">);</span><span class="pln"> </span><span class="com">// null</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="194" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-03-dom-navigation-ex06" src="https://codepen.io/Hsoub/embed/preview/JjRgYEW?height=194&amp;theme-id=light&amp;default-tab=js,result">See the Pen JS-p2-03-dom-navigation-ex06 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	سبب ذلك أنّ أب العقدة الجذر <code>document.documentElement</code> (التي تمثلّ <code>&lt;html&gt;</code>) هو <code>document</code>، و <code>document</code> ليس عقدة عنصريّة. فلهذا تعيده <code>parentNode</code> ولا تعيده <code>parentElement</code>.
</p>

<p>
	قد يفيد هذا التفصيل إذا ما أردنا التنقّل صعودا من عنصرٍ ما <code>elem</code> إلى <code>&lt;html&gt;</code>، لكن دون الوصول إلى <code>document</code>.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4824_31" style="">
<span class="kwd">while</span><span class="pun">(</span><span class="pln">elem </span><span class="pun">=</span><span class="pln"> elem</span><span class="pun">.</span><span class="pln">parentElement</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="com">// &lt;html&gt; اصعد إلى غاية</span><span class="pln">
  alert</span><span class="pun">(</span><span class="pln"> elem </span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<hr>
<p>
	لنُعدّل أحد اﻷمثلة التي في اﻷعلى. استبدل <code>childNodes</code> بـ <code>children</code> . ستظهر لك الآن العناصر فقط:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_4824_33" style="">
<span class="tag">&lt;html&gt;</span><span class="pln">
</span><span class="tag">&lt;body&gt;</span><span class="pln">
  </span><span class="tag">&lt;div&gt;</span><span class="pln">Begin</span><span class="tag">&lt;/div&gt;</span><span class="pln">

  </span><span class="tag">&lt;ul&gt;</span><span class="pln">
    </span><span class="tag">&lt;li&gt;</span><span class="pln">Information</span><span class="tag">&lt;/li&gt;</span><span class="pln">
  </span><span class="tag">&lt;/ul&gt;</span><span class="pln">

  </span><span class="tag">&lt;div&gt;</span><span class="pln">End</span><span class="tag">&lt;/div&gt;</span><span class="pln">

  </span><span class="tag">&lt;script&gt;</span><span class="pln">
    </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let elem of document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">children</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      alert</span><span class="pun">(</span><span class="pln">elem</span><span class="pun">);</span><span class="pln"> </span><span class="com">// DIV, UL, DIV, SCRIPT</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="tag">&lt;/script&gt;</span><span class="pln">
  ...
</span><span class="tag">&lt;/body&gt;</span><span class="pln">
</span><span class="tag">&lt;/html&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-03-dom-navigation-ex07" src="https://codepen.io/Hsoub/embed/preview/QWKejdR?height=265&amp;theme-id=light&amp;default-tab=html,result">See the Pen JS-p2-03-dom-navigation-ex07 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<h2>
	المزيد من الروابط: الجدوال
</h2>

<p>
	تناولنا إلى حدّ الآن خاصّيّات التنقّل اﻷساسيّة.
</p>

<p>
	قد تُتيح بعض أصناف العناصر في DOM خاصّيات إضافيّة تتميّز بها دون غيرها، لمزيدٍ من التسهيل.
</p>

<p>
	تُعدّ الجداول مثالا جيّدا لذلك، وتمثّل حالة خاصّة اﻷهميّة:
</p>

<p>
	يدعم عنصر <strong><code>&lt;table&gt;</code></strong> (إضافة إلى ما ذُكر في اﻷعلى) الخاصّيّات التالية:
</p>

<ul>
<li>
		<code>table.rows</code> -- مجموعة عناصر <code>&lt;tr&gt;</code> التي في الجدول.
	</li>
	<li>
		<code>table.caption/tHead/tFoot</code> -- تشير إلى العناصر <code>caption</code> و <code>thead</code> و <code>tfoot</code>.
	</li>
	<li>
		<code>table.tBodies</code> -- مجموعة عناصر <code>&lt;tbody&gt;</code> (قد تكون هناك عدّةٌ منها كما ينصّ على ذلك المعيار، لكن سيكون هناك حتمًا واحد على اﻷقل -- حتى وإن لم يوجد في مصدر HTML، فسيضعه المتصفّح في DOM).
	</li>
</ul>
<p>
	تُتيح العناصر <strong><code>&lt;thead&gt;</code></strong> و <strong><code>&lt;tfoot&gt;</code></strong> و <strong><code>&lt;tbody&gt;</code></strong> خاصّيّة <code>rows</code> :
</p>

<ul>
<li>
		<code>tbody.rows</code> -- مجموعة عناصر <code>&lt;tr&gt;</code> التي بداخله.
	</li>
</ul>
<p>
	<strong><code>&lt;tr&gt;</code></strong>:
</p>

<ul>
<li>
		<code>tr.cells</code> -- مجموعة الخانات <code>&lt;td&gt;</code> و <code>&lt;th&gt;</code> التي بداخل <code>&lt;tr&gt;</code>.
	</li>
	<li>
		<code>tr.sectionRowIndex</code> -- موضع <code>&lt;tr&gt;</code> بداخل الـ <code>&lt;thead&gt;</code> أو <code>&lt;tbody&gt;</code> أو <code>&lt;tfoot&gt;</code> الذي يضمّه.
	</li>
	<li>
		<code>tr.rowIndex</code> -- رقم <code>&lt;tr&gt;</code> بالنسبة للجدول ككلّ (أي بين جميع أسطر الجدول).
	</li>
</ul>
<p>
	<strong><code>&lt;td&gt;</code></strong> و <strong><code>&lt;th&gt;</code></strong>:
</p>

<ul>
<li>
		<code>td.cellIndex</code> -- رقم الخانة بداخل السطر الذي يضمّها.
	</li>
</ul>
<p>
	هذا مثال عن استعمالها:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_4824_35" style="">
<span class="tag">&lt;table</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"table"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;tr&gt;</span><span class="pln">
    </span><span class="tag">&lt;td&gt;</span><span class="pln">one</span><span class="tag">&lt;/td&gt;&lt;td&gt;</span><span class="pln">two</span><span class="tag">&lt;/td&gt;</span><span class="pln">
  </span><span class="tag">&lt;/tr&gt;</span><span class="pln">
  </span><span class="tag">&lt;tr&gt;</span><span class="pln">
    </span><span class="tag">&lt;td&gt;</span><span class="pln">three</span><span class="tag">&lt;/td&gt;&lt;td&gt;</span><span class="pln">four</span><span class="tag">&lt;/td&gt;</span><span class="pln">
  </span><span class="tag">&lt;/tr&gt;</span><span class="pln">
</span><span class="tag">&lt;/table&gt;</span><span class="pln">

</span><span class="tag">&lt;script&gt;</span><span class="pln">
  </span><span class="com">// (السطر اﻷوّل، والعمود الثاني) "two" حدّد الخانة التي فيها</span><span class="pln">
  let td </span><span class="pun">=</span><span class="pln"> table</span><span class="pun">.</span><span class="pln">rows</span><span class="pun">[</span><span class="lit">0</span><span class="pun">].</span><span class="pln">cells</span><span class="pun">[</span><span class="lit">1</span><span class="pun">];</span><span class="pln">
  td</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">backgroundColor </span><span class="pun">=</span><span class="pln"> </span><span class="str">"red"</span><span class="pun">;</span><span class="pln"> </span><span class="com">// لوّنها</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-03-dom-navigation-ex08" src="https://codepen.io/Hsoub/embed/JjRgYWW?height=265&amp;theme-id=light&amp;default-tab=html,result">See the Pen JS-p2-03-dom-navigation-ex08 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	للاطلاع على المواصفة: <a href="https://html.spec.whatwg.org/multipage/tables.html" rel="external nofollow">tabular data</a>.
</p>

<p>
	هناك أيضا المزيد من خاصّيات التنقّل التي تتعلّق بنماذج HTML (أي forms). سنقف عندها لاحقا عندما نبدأ العمل بالنماذج.
</p>

<h2>
	الملخص
</h2>

<p>
	إنطلاقًا من أيّ عقدةٍ في DOM، يمكن الذهاب إلى العقد المجاورة لها مباشرة بواسطة خاصّيّات التنقّل.
</p>

<p>
	تنقسم هذه الخاصيّات إلى فئتين رئيسيّتن:
</p>

<ul>
<li>
		لجميع العقد:
		<ul>
<li>
				<code>parentNode</code>
			</li>
			<li>
				<code>childNodes</code>
			</li>
			<li>
				<code>firstChild</code>
			</li>
			<li>
				<code>lastChild</code>
			</li>
			<li>
				<code>previousSibling</code>
			</li>
			<li>
				<code>nextSibling</code>
			</li>
		</ul>
</li>
	<li>
		للعقد العنصريّة فقط:
		<ul>
<li>
				<code>parentElement</code>
			</li>
			<li>
				<code>children</code>
			</li>
			<li>
				<code>firstElementChild</code>
			</li>
			<li>
				<code>lastElementChild</code>
			</li>
			<li>
				<code>previousElementSibling</code>
			</li>
			<li>
				<code>nextElementSibling</code>
			</li>
		</ul>
</li>
</ul>
<p>
	تُتيح بعض أصناف العقد في DOM كالجداول مثلا، خاصّيّات ومجموعات إضافيّة تمكّن من الوصول إلى محتواها.
</p>

<h2>
	التمارين
</h2>

<h3>
	اﻷبناء في DOM
</h3>

<p>
	اﻷهمية: 5
</p>

<p>
	لاحظ هذه الصفحة:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_4824_37" style="">
<span class="tag">&lt;html&gt;</span><span class="pln">
</span><span class="tag">&lt;body&gt;</span><span class="pln">
  </span><span class="tag">&lt;div&gt;</span><span class="pln">Users:</span><span class="tag">&lt;/div&gt;</span><span class="pln">
  </span><span class="tag">&lt;ul&gt;</span><span class="pln">
    </span><span class="tag">&lt;li&gt;</span><span class="pln">John</span><span class="tag">&lt;/li&gt;</span><span class="pln">
    </span><span class="tag">&lt;li&gt;</span><span class="pln">Pete</span><span class="tag">&lt;/li&gt;</span><span class="pln">
  </span><span class="tag">&lt;/ul&gt;</span><span class="pln">
</span><span class="tag">&lt;/body&gt;</span><span class="pln">
</span><span class="tag">&lt;/html&gt;</span></pre>

<p>
	اعط طريقة واحدة على اﻷقلّ للوصول إلى كلٍّ من عقد DOM التالية:
</p>

<ul>
<li>
		العقدة <code>&lt;div&gt;</code>؟
	</li>
	<li>
		العقدة <code>&lt;ul&gt;</code>؟
	</li>
	<li>
		عقدة <code>&lt;li&gt;</code> الثانية (التي فيها Pete)؟
	</li>
</ul>
<h3>
	الحل
</h3>

<p>
	هناك عدّة طرق، على سبيل المثال:
</p>

<p>
	العقدة <code>&lt;div&gt;</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4824_39" style="">
<span class="pln">document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">firstElementChild
</span><span class="com">// أو</span><span class="pln">
document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">children</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]</span><span class="pln">
</span><span class="com">// أو -- لاحظ أن العقدة الأولى فراغ، لذا نأخذ الثانية   </span><span class="pln">
document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">childNodes</span><span class="pun">[</span><span class="lit">1</span><span class="pun">]</span></pre>

<p>
	العقدة <code>&lt;ul&gt;</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4824_41" style="">
<span class="pln">document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">lastElementChild
</span><span class="com">// أو</span><span class="pln">
document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">children</span><span class="pun">[</span><span class="lit">1</span><span class="pun">]</span></pre>

<p>
	عقدة <code>&lt;li&gt;</code> الثانية (التي فيها Pete):
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4824_43" style="">
<span class="com">// ومن ثمّ تحصيل آخر أبنائه العناصر &lt;ul&gt; تحصيل</span><span class="pln">
document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">lastElementChild</span><span class="pun">.</span><span class="pln">lastElementChild</span></pre>

<hr>
<h3>
	سؤال عن الإخوة
</h3>

<p>
	اﻷهميّة: 5
</p>

<p>
	إذا كانت <code>elem</code> عقدةً عنصريّة من DOM …
</p>

<ul>
<li>
		هل صحيح أنّ <code>elem.lastChild.nextSibling</code> دائمًا <code>null</code>؟
	</li>
	<li>
		هل صحيح أنّ <code>elem.children[0].previousSibling</code> دائمًا <code>null</code>؟
	</li>
</ul>
<h3>
	الحل
</h3>

<ol>
<li>
		نعم، ذلك صحيح. يكون <code>elem.lastChild</code> دائما آخر اﻷبناء، فليس لديه <code>nextSibling</code>.
	</li>
	<li>
		لا ليس ذلك صحيحا، ﻷنّ <code>[elem.children[0</code> هو أوّل ابنٍ <em>بين العناصر</em>، وقد تأتي قبله عقدٌ غير عنصريّة. فلا تكون بذلك <code>previousSibling</code> هي <code>null</code> بالضرورة، بل قد تكون عقدةً نصيّة مثلا.
	</li>
</ol>
<p>
	يرجى الانتباه إلى أنّه في كلتا الحالتين، إذا لم يكن هناك أبناء فسيُحدث ذلك خطأً.
</p>

<p>
	إذا لم يكن هناك أبناء، فإنّ <code>elem.lastChild</code> هو <code>null</code> فلا يمكننا الوصول إلى <code>elem.lastChild.nextSibling</code>، وتكون أيضا المجموعة <code>elem.children</code> فارغة (كمصفوفة فارغة [ ]).
</p>

<hr>
<h3>
	اختر الخانات القُطريّة
</h3>

<p>
	اﻷهميّة: 5
</p>

<p>
	اكتب الشفرة التي تُلوّن جميع الخانات التي على قُطر الجدول باﻷحمر.
</p>

<p>
	ستحتاج إلى تحصيل جميع الخانات <code>&lt;td&gt;</code> القطريّة من الجدول <code>&lt;table&gt;</code> وتلوينها باستخدام الشفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4824_45" style="">
<span class="com">// إلى خانة الجدول td تشير</span><span class="pln">
td</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">backgroundColor </span><span class="pun">=</span><span class="pln"> </span><span class="str">'red'</span><span class="pun">;</span></pre>

<p>
	يجب أن تكون النتيجة كالتالي:
</p>

<p>
	<iframe class="code-result__iframe" data-trusted="1" style="height:180px" src="https://en.js.cx/task/select-diagonal-cells/solution/"></iframe>
</p>

<p>
	<a href="https://plnkr.co/edit/nuNlB97squ4Hgwrg?p=preview" rel="external nofollow">افتح البيئة التجريبيّة لإنجاز التمرين</a>
</p>

<h3>
	الحل
</h3>

<p>
	سنستخدم خاصّيّات <code>rows</code> و <code>cells</code> للوصول إلى الخانات القطريّة.
</p>

<p>
	<a href="https://plnkr.co/edit/mT7Hlxa5XBhtHzLt?p=preview" rel="external nofollow">شاهد الحلّ في البيئة التجريبيّة</a>
</p>

<hr>
<p>
	ترجمة وبتصرف لمقال <a href="https://javascript.info/dom-navigation" rel="external nofollow">Walking the DOM</a> من كتاب <a href="https://javascript.info/" rel="external nofollow">The Modern JavaScript Tutorial</a>
</p>
]]></description><guid isPermaLink="false">1105</guid><pubDate>Wed, 20 Jan 2021 13:00:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x62A;&#x639;&#x631;&#x641; &#x639;&#x644;&#x649; &#x634;&#x62C;&#x631;&#x629; DOM &#x644;&#x62A;&#x639;&#x62F;&#x64A;&#x644;&#x647;&#x627; &#x639;&#x628;&#x631; &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A;</title><link>https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%AA%D8%B9%D8%B1%D9%81-%D8%B9%D9%84%D9%89-%D8%B4%D8%AC%D8%B1%D8%A9-dom-%D9%84%D8%AA%D8%B9%D8%AF%D9%8A%D9%84%D9%87%D8%A7-%D8%B9%D8%A8%D8%B1-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r1104/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_01/600fd6ad518ff_--DOM.png.c2738054934ad3a955781a6ea5d9f9dd.png" /></p>

<p>
	تعدّ الوسوم (tags) أساس مستندات HTML. ويُمثَّل كلُّ وسمٍ منها في نموذج كائن المستند (DOM) بكائن. كما يُمثَّل النصّ الذي بداخل الوسم بكائن أيضا. وتعدّ الوسوم المتشعبة عن وسم آخر "أبناءً" لذلك الوسم.
</p>

<p>
	يمكننا الوصول لكلّ هذه الكائنات من خلال جافاسكربت، ونستطيع بواسطتها التعديل على الصفحة. فعلى سبيل المثال، يمثّل الكائن <code>document.body</code> وسم <code>&lt;body&gt;</code>، وبتنفيذ الشفرة التالية يصير لون <code>&lt;body&gt;</code> أحمر لمدّة 3 ثوانٍ:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9182_7" style="">
<span class="pln">document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">background </span><span class="pun">=</span><span class="pln"> </span><span class="str">'red'</span><span class="pun">;</span><span class="pln"> </span><span class="com">// جعل الخلفية حمراء اللون</span><span class="pln">

setTimeout</span><span class="pun">(()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">background </span><span class="pun">=</span><span class="pln"> </span><span class="str">''</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3000</span><span class="pun">);</span><span class="pln"> </span><span class="com">// ارجاعها كما كانت</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-02-dom-nodes-ex01" src="https://codepen.io/Hsoub/embed/preview/YzGmXJZ?height=265&amp;theme-id=light&amp;default-tab=js,result">See the Pen JS-p2-02-dom-nodes-ex01 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	استعملنا هنا خاصّيّة <code>style.background</code> لتغيير لون خلفيّة <code>document.body</code>، وهناك العديد من الخاصّيّات اﻷخرى مثل:
</p>

<ul>
<li>
		<code>innerHTML</code> -- محتوى HTML الذي بداخل العقدة.
	</li>
	<li>
		<code>offsetWidth</code> -- مقدار عرض العقدة (بالبكسل).
	</li>
	<li>
		… إلى غير ذلك.
	</li>
</ul>
<p>
	سنتعلم قريبا المزيد من الطرق لمعالجة DOM، لكن نحتاج أوّلا إلى التعرّف على بنيته.
</p>

<h2>
	مثال عن DOM
</h2>

<p>
	لنبدأ بالمستند البسيط التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_9182_9" style="">
<span class="dec">&lt;!DOCTYPE HTML&gt;</span><span class="pln">
</span><span class="tag">&lt;html&gt;</span><span class="pln">
</span><span class="tag">&lt;head&gt;</span><span class="pln">
  </span><span class="tag">&lt;title&gt;</span><span class="pln">About elk</span><span class="tag">&lt;/title&gt;</span><span class="pln">
</span><span class="tag">&lt;/head&gt;</span><span class="pln">
</span><span class="tag">&lt;body&gt;</span><span class="pln">
  The truth about elk.
</span><span class="tag">&lt;/body&gt;</span><span class="pln">
</span><span class="tag">&lt;/html&gt;</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" style="width: 100%;" title="JS-p2-02-dom-nodes-ex02" src="https://codepen.io/Hsoub/embed/RwGXPqg?height=265&amp;theme-id=light&amp;default-tab=html,result">See the Pen JS-p2-02-dom-nodes-ex02 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	يمثِّل DOM مستند HTML بواسطة بنية شجريّة من الوسوم، كما في الصورة التالية:
</p>

<p style="text-align: center;">
	<img alt="001.png" class="ipsImage ipsImage_thumbnailed" data-fileid="56426" data-unique="svf0w6sff" src="https://academy.hsoub.com/uploads/monthly_2021_01/001.png.fcbaa646bf244301ea30b1315c31df70.png"></p>

<p>
	كل عقدة من هذه الشجرة هي كائن.
</p>

<p>
	تُمثَّل الوسوم <em>بعقدٍ عنصريّة</em> element nodes (أو عناصر elements باختصار) وتشكّل بنية الشّجرة. فعند الجذر توجد<code>&lt;html&gt;</code> ، و<code>&lt;head&gt;</code> و <code>&lt;body&gt;</code> هما أبناؤها، إلى آخر ذلك.
</p>

<p>
	يُمثَّل النّص الذي بداخل العناصر <em>بعقدٍ نصّيّة</em> وهي معلّمة في الصّورة بـ <code>text#</code>. لا تحتوي العقد النّصية إلا على سلاسل نصيّة (string)، ولا يمكن أن يكون لها أبناء، وتكون دائما بمثابة ورقةٍ للشجرة.
</p>

<p>
	على سبيل المثال، يحوي وسم <code>&lt;title&gt;</code> على النصّ <code>"About elk"</code>.
</p>

<p>
	لاحظ وجود هذه المحارف الخاصّة (special characters) في العقد النصّيّة:
</p>

<ul>
<li>
		السطر الجديد: <code>↵</code> (يُعرف في جافاسكربت بـ <code>n\</code>).
	</li>
	<li>
		الفراغ: <code>␣</code>.
	</li>
</ul>
<p>
	يعدّ السطر الجديد والفراغ محارف صحيحة، تماما كالحروف واﻷرقام، وتُكوّن بدورها عقدا نصّيّة وتصير جزءًا من DOM. ففي المثال أعلاه، يحوي وسم <code>&lt;head&gt;</code> بعض الفراغات قبل <code>&lt;title&gt;</code>، ويكوّن ذلك النّص عقدة نصّيّة (تحوي سطرا جديدا وبعض الفراغات فقط).
</p>

<p>
	يُستثنى من ذلك شيئان:
</p>

<ul>
<li>
		تُهمل الفراغات واﻷسطر الجديدة التي قبل <code>&lt;head&gt;</code> لأسباب تاريخيّة.
	</li>
	<li>
		إذا وضعنا شيئا ما بعد <code>&lt;body/&gt;</code>، فإنه يُنقل تلقائيّا إلى آخر <code>body</code>، ﻷنّ مواصفة HTML تشترط أن يكون جميع المحتوى موجودا داخل <code>&lt;body&gt;</code>. لذا فلا يمكن أن تكون هناك أيّة فراغات بعد <code>&lt;body/&gt;</code>.
	</li>
</ul>
<p>
	في غير ذلك من الحالات، فاﻷمر واضح؛ إذا كانت هناك فراغات في المستند فإنّها تصير عقدا نصّيّة (كغيرها من المحرّفات) في DOM، وإن أزلناها فلن تكون هناك أيّ منها.
</p>

<p>
	هذا مثال لعقد نصيّة لا تحوي أيّة فراغات:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_9182_11" style="">
<span class="dec">&lt;!DOCTYPE HTML&gt;</span><span class="pln">
</span><span class="tag">&lt;html&gt;&lt;head&gt;&lt;title&gt;</span><span class="pln">About elk</span><span class="tag">&lt;/title&gt;&lt;/head&gt;&lt;body&gt;</span><span class="pln">The truth about elk.</span><span class="tag">&lt;/body&gt;&lt;/html&gt;</span></pre>

<p style="text-align: center;">
	<img alt="002.png" class="ipsImage ipsImage_thumbnailed" data-fileid="56427" data-unique="r7hhy0iiv" src="https://academy.hsoub.com/uploads/monthly_2021_01/002.png.996ea14c716f9d223c17d42e838e96cc.png"></p>

<p>
	لا تُظهر أدوات المتصفّح (التي سنتطرق لها لاحقا) عند تعاملها مع DOM عادةً الفراغات التي في أوّل النّصّ وآخره، ولا العقد النصّيّة الفارغة (كالتي تنجم عن إنهاء السطر) بين الوسوم. توفّر أدوات المتصفّح بذلك المساحة على الشاشة. قد نحذفها أيضا في ما يأتي صورٍ لـ DOM إذا لم يكن في إظهارها فائدة. لا تؤثر هذه الفراغات عادة على كيفيّة عرض المستند.
</p>

<h2>
	التصحيح التلقائي
</h2>

<p>
	إذا صادف المتصفّح مستند HTML خاطئ التنسيق، فإنّه يصحّحه تلقائيّا عند بناء DOM.
</p>

<p>
	على سبيل المثال، يكون <code>&lt;html&gt;</code> دائما هو الوسم اﻷعلى. حتى وإن لم يوجد في المستند، فإنّه سُيوجد في DOM، لأن المتصفّح سيُنشئه. وكذلك الشأن مع <code>&lt;body&gt;</code>.
</p>

<p>
	فإذا كان ملف HTML عبارةً عن كلمة واحدة <code>"Hello"</code>، فإنّ المتصفّح سيلفُّه وسط <code>&lt;html&gt;</code> و <code>&lt;body&gt;</code> ويضيف لهما <code>&lt;head&gt;</code> كما يلزم، ويصير بذلك DOM:
</p>

<p style="text-align: center;">
	<img alt="003.png" class="ipsImage ipsImage_thumbnailed" data-fileid="56428" data-unique="915kllxfl" src="https://academy.hsoub.com/uploads/monthly_2021_01/003.png.69d361f4635c3585c5f305c721aea0f0.png"></p>

<p>
	عند توليد DOM، تعالج المتصفّحات تلقائيّا الأخطاء التي في المستند، كعدم إغلاق الوسوم وغير ذلك.
</p>

<p>
	فإذا كان في المستند وسوم لم تُغلق:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_9182_13" style="">
<span class="tag">&lt;p&gt;</span><span class="pln">Hello
</span><span class="tag">&lt;li&gt;</span><span class="pln">Mom
</span><span class="tag">&lt;li&gt;</span><span class="pln">and
</span><span class="tag">&lt;li&gt;</span><span class="pln">Dad</span></pre>

<p>
	فإنّ المتصفّح يستعيد الأجزاء المفقودة عندما يطّلع على الوسوم:
</p>

<p style="text-align: center;">
	<img alt="004.png" class="ipsImage ipsImage_thumbnailed" data-fileid="56429" data-unique="6wafc2cni" src="https://academy.hsoub.com/uploads/monthly_2021_01/004.png.087fbbf940643ede5cbe442f6e1b68aa.png"></p>

<hr>
<p>
	<strong>للجداول دائما <code>&lt;tbody&gt;</code></strong>
</p>

<p>
	تعدّ الجداول "حالة خاصّة" مثيرة للاهتمام. فوفقًا لمواصفة DOM يجب أن يكون للجداول العنصر <code>&lt;tbody&gt;</code>، لكن يُسمح (رسميًّا) لنصوص HTML أن تسقطه. فينشئ المتصفح حينها <code>&lt;tbody&gt;</code> في DOM تلقائيّا.
</p>

<p>
	فتؤدّي مثلا شفرة HTML هذه:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_9182_15" style="">
<span class="tag">&lt;table</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"table"</span><span class="tag">&gt;&lt;tr&gt;&lt;td&gt;</span><span class="pln">1</span><span class="tag">&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;</span></pre>

<p>
	إلى بنية DOM التالية:
</p>

<p style="text-align: center;">
	<img alt="005.png" class="ipsImage ipsImage_thumbnailed" data-fileid="56430" data-unique="tlpk4ipp1" src="https://academy.hsoub.com/uploads/monthly_2021_01/005.png.6b772a25ed9df47b990151db36990489.png"></p>

<p>
	أرأيت؟ ظهر <code>&lt;tbody&gt;</code> من لاشيء. ينبغي الانتباه لهذا عند التعامل مع الجداول لتفادي المفاجآت.
</p>

<hr>
<h2>
	أنواع أخرى من العقد
</h2>

<p>
	هناك أنواع أخرى من العقد ما عدا العقد العنصريّة والنصيّة.
</p>

<p>
	فهناك مثلا التعليقات.
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_9182_17" style="">
<span class="dec">&lt;!DOCTYPE HTML&gt;</span><span class="pln">
</span><span class="tag">&lt;html&gt;</span><span class="pln">
</span><span class="tag">&lt;body&gt;</span><span class="pln">
  The truth about elk.
  </span><span class="tag">&lt;ol&gt;</span><span class="pln">
    </span><span class="tag">&lt;li&gt;</span><span class="pln">An elk is a smart</span><span class="tag">&lt;/li&gt;</span><span class="pln">
    </span><span class="com">&lt;!-- comment --&gt;</span><span class="pln">
    </span><span class="tag">&lt;li&gt;</span><span class="pln">...and cunning animal!</span><span class="tag">&lt;/li&gt;</span><span class="pln">
  </span><span class="tag">&lt;/ol&gt;</span><span class="pln">
</span><span class="tag">&lt;/body&gt;</span><span class="pln">
</span><span class="tag">&lt;/html&gt;</span></pre>

<p style="text-align: center;">
	<img alt="06.png" class="ipsImage ipsImage_thumbnailed" data-fileid="56437" data-unique="sw85ru4dk" src="https://academy.hsoub.com/uploads/monthly_2021_01/06.png.c91ae5ae8fb3c315f52620cebb0356e3.png"></p>

<p>
	يمكننا في الصورة أعلاه ملاحظة نوع جديد من العقد -- <em>العقد التعليقيّة</em> ، معلّمة بـ <code>comment#</code> ، بين عقدتين نصّيّتين.
</p>

<p>
	لكن قد نتساءل -- لماذا تضاف التعليقات إلى DOM؟ فلا تأثير لها على التمثيل البصريّ بأيّ شكل من اﻷشكال. هذا صحيح، لكن هناك قاعدة تقول: كلُّ ما وُجد في HTML، فلا بدّ أن يوجد أيضا في شجرة DOM.
</p>

<p>
	<strong>كلّ ما يحويه HTML، حتّى التعليقات، يصير جزءًا من DOM.</strong>
</p>

<p>
	حتّى تعليمة <code>&lt;...DOCTYPE!&gt;</code> التي في أوّل HTML هي أيضا عقدة من DOM. هي موجودة في شجرة DOM قبل <code>&lt;html&gt;</code> مباشرة. لن نمسّ تلك العقدة، ولن نرسمها حتى في المخططات، لكنّها موجودة.
</p>

<p>
	بل إنّ كائن <code>document</code> الذي يمثل المستند بأكمله هو، اصطلاحًا، عقدة من DOM أيضا.
</p>

<p>
	هناك <a href="https://dom.spec.whatwg.org/#node" rel="external nofollow">12 نوعا من العقد</a>، لكن نتعامل عادةً مع أربعة منها فقط:
</p>

<ol>
<li>
		<code>document</code> -- "نقطة الدخول" إلى DOM.
	</li>
	<li>
		العقد العنصريّة -- وسوم HTML التي تمثل لبِنات الشجرة اﻷساسيّة.
	</li>
	<li>
		العقد النصّيّة -- تحتوي على نصّ فقط.
	</li>
	<li>
		التعليقات -- نضع فيها بعض المعلومات أحيانا. هي لا تُعرض، ولكن يستطيع جافاسكربت قراءتها من خلال DOM.
	</li>
</ol>
<h2>
	عاينه بنفسك
</h2>

<p>
	لمعاينة البنية الآنيّة لـ DOM، جرّب <a href="http://software.hixie.ch/utilities/js/live-dom-viewer/" rel="external nofollow">Live DOM Viewer</a>. عليك فقط أن تدخل المستند، وسيظهر لك على شكل DOM حالًا.
</p>

<p>
	يمكن أيضا تفحّص DOM باستخدام أدوات المطوّر (developer tools) في المتصفّح، وهي في الحقيقة ما نستعمله عند التطوير.
</p>

<p>
	للقيام بذلك، افتح صفحة <a href="elk.html" rel="">elk.html</a>، ثمّ فعّل أدوات المطوّر في المتصفّح بالضغط على <code>F12</code>، وانتقل إلى لسان Elements (بمعنى عناصر).
</p>

<p>
	يُفترض أن تبدو كما في الصورة:
</p>

<p style="text-align: center;">
	<img alt="elk.png" class="ipsImage ipsImage_thumbnailed" data-fileid="56435" data-unique="w0wq8x5r8" src="https://academy.hsoub.com/uploads/monthly_2021_01/elk.png.fd66465710ff16832edbea2d48d2b14c.png"></p>

<p>
	يمكنك مشاهدة DOM، والنقر على على عناصره لاستعراض تفاصيلها وما إلى ذلك.
</p>

<p>
	يُرجى التنبّه إلى أن بنية DOM مبسّطة في أدوات المطوّر. فتظهر العقد النصّيّة كمجرّد نصّ، وليست هناك عقد نصّيّة فارغة (أي تتكوّن من فراغات فقط) إطلاقًا. لكن لا بأس بذلك، إذ ما نهتمّ به في الغالب هي العقد العنصريّة.
</p>

<p>
	بالنقر على الزرالذي على شكل مؤشر في أقصى الزاوية اليسرى من اﻷعلى يمكننا اختيار عقدة من الصفحة باستخدام الفأرة (أو أيٍّ من أجهزة التأشير اﻷخرى) و "فحصها" (بالانتقال إلى موضعها في لسان العناصر). يفيد هذا كثيرا عندما تكون صفحة HTML (وما يقابلها من DOM) التي لدينا كبيرة جدا، ونود أن نرى مكان عنصر معيّن منها.
</p>

<p>
	كما يمكن أيضا فعل ذلك عن طريق النقر بالزر اﻷيمن على صفحة الويب ومن ثمّ اختيار "Inspect" (أي تفحّص) من القائمة المنبثقة.
</p>

<p style="text-align: center;">
	<img alt="inspect.png" class="ipsImage ipsImage_thumbnailed" data-fileid="56436" data-unique="yf94meqag" src="https://academy.hsoub.com/uploads/monthly_2021_01/inspect.png.1ed6d12f642cf5db09f401c153279277.png"></p>

<p>
	توجد في الجزء اﻷيمن من اﻷدوات اﻷلسنة الفرعية التالية:
</p>

<ul>
<li>
		<strong>Styles</strong> (بمعنى الأنماط) -- تمكّننا من رؤية قواعد CSS المطبّقة على العنصر الحاليّ قاعدةً بقاعدة، بما في ذلك القواعد المضمّنة (باللون الرمادي). يمكن تقريبًا تعديل كلّ شيء من مكانه، بما في ذلك أبعاد (dimensions) وهوامش (margins) وحشوات (paddings) الصندوق (box) من أسفل اللسان.
	</li>
	<li>
		<strong>Computed</strong> (بمعنى المحسوبة) -- لرؤية تنسيقات CSS المطبّقة على العنصر مرتّبةً حسب الخاصّيّة (property): كلّ خاصّيّة تقابلها القاعدة التي منحتها (بما في ذلك التنسيقات المورّثة وما إلى ذلك).
	</li>
	<li>
		<strong>Event Listeners</strong> (بمعنى مستمعي اﻷحداث) -- لرؤية مستمعي اﻷحداث المرفقة مع عناصر DOM (سنتناول ذلك في مقالات لاحقة).
	</li>
</ul>
<p>
	أفضل طريقة لدراسة كلّ هذه اﻷقسام هي بالنقر هنا وهناك. معظم القيم قابلة للتعديل من مكانها.
</p>

<h2>
	التعامل مع الطرفية (console)
</h2>

<p>
	عند تعاملنا مع DOM قد نودّ تطبيق جافاسكربت عليه، كأن نأخذ إحدى العقد، ونجري عليها شِفرة ما لمعرفة النتيجة. هذه بعض الطرق لكيفيّة التنقل بين لسان العناصر والطرفيّة.
</p>

<p>
	بدايةً:
</p>

<ol>
<li>
		حدّد أوّل <code>&lt;li&gt;</code> في لسان العناصر.
	</li>
	<li>
		اضغط زر <code>Esc</code> -- سيفتح ذلك الطرفيّة تحت لسان العناصر مباشرة.
	</li>
</ol>
<p>
	يكون آخر العناصر التي حدّدناها محفوظا في المتغيّر <code>0$</code> ، والذي حدّدناه قبل ذلك في <code>1$</code> وهكذا.
</p>

<p>
	يمكننا تنفيذ أوامر عليها. فمثلا، يغيّر اﻷمر ‎<code>‎$0.style.background = 'red'‎</code> لون عنصر القائمة المحدَّد إلى اﻷحمر كما في الصّورة:
</p>

<p style="text-align: center;">
	<img alt="domconsole0 .png" class="ipsImage ipsImage_thumbnailed" data-fileid="56432" data-unique="c5r4izop6" src="https://academy.hsoub.com/uploads/monthly_2021_01/600fd624a53de_domconsole0.png.b182a1502e95a05352495680669e128b.png"></p>

<p>
	بهذه الطريقة تُنقل العقد من لسان العناصر إلى الطرفية.
</p>

<p>
	يمكن أيضا فعل العكس. فإذا كان لدينا متغيّر يشير إلى عقدة ما، يمكننا استخدام اﻷمر <code>(inspect(node</code> (حيث node هو اسم المتغيّر) في الطرفيّة لرؤيتها في لسان العناصر.
</p>

<p>
	أو يمكننا فقط طباعة عقدة DOM في الطرفية وتفحصّها "من مكانها"، كما هو الحال مع <code>document.body</code> في اﻷسفل:
</p>

<p style="text-align: center;">
	<img alt="domconsole1.png" class="ipsImage ipsImage_thumbnailed" data-fileid="56433" data-unique="pktwtmg7y" src="https://academy.hsoub.com/uploads/monthly_2021_01/domconsole1.png.aea6773dc7fba4bbdc24648378af0124.png"></p>

<p>
	لا تُستخدم هذه الطرق إلا عند تنقيح اﻷخطاء بالطبع. ابتداءً من المقال الموالي، سنستخدم جافاسكربت للوصول إلى DOM والتعديل عليه.
</p>

<p>
	تساعد أدوات المطوّر في المتصفّح كثيرا أثناء التطوير، إذ يمكن من خلالها تفحّص DOM، وتجريب أشياء مختلفة لمعرفة ما قد يحدث من أخطاء.
</p>

<h2>
	خلاصة
</h2>

<p>
	يُمثًّل مستند HTML/XML في المتصفّح بواسطة شجرة DOM.
</p>

<ul>
<li>
		تصير الوسوم عقدًا عنصريّة وتشكّل بنية الشجرة.
	</li>
	<li>
		تصير النصوص عقدًا نصّيّة.
	</li>
	<li>
		… إلى غير ذلك، فلِكلّ ما يوجد في HTML مكانه في DOM، حتّى التعليقات.
	</li>
</ul>
<p>
	يمكننا استخدام أدوات المطوّر لتفحّص DOM وتعديله يدويّا.
</p>

<p>
	اقتصرنا هنا كبدايةٍ على اﻷساسيّات من أهمّ العمليّات وأكثرها استخداما. هناك توثيق شامل ﻷدوات المطوّر في متصفّح Chrome على <a href="https://developers.google.com/web/tools/chrome-devtools." ipsnoembed="false" rel="external nofollow">https://developers.google.com/web/tools/chrome-devtools.</a> أفضل طريقة لتعلم هذه اﻷدوات هو النقر هنا وهناك، وقراءة ما في القوائم، فمعظم الخيارات واضحة. لاحقا، عندما تتقن استخدامها عموما، طالع التوثيق والتقط الباقي.
</p>

<p>
	لعُقد DOM خاصّيّات وتوابع تمكنّنا من التنقّل بينها والتعديل عليها والتجوّل في الصفحة وغير ذلك. هذا ما سنتناوله في المقال التالي.
</p>

<p>
	ترجمة وبتصرف لمقال <a href="https://javascript.info/dom-nodes" rel="external nofollow">DOM tree</a> من كتاب <a href="https://javascript.info/" rel="external nofollow">The Modern JavaScript Tutorial</a>
</p>
]]></description><guid isPermaLink="false">1104</guid><pubDate>Mon, 18 Jan 2021 13:00:00 +0000</pubDate></item><item><title>&#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A; &#x641;&#x64A; &#x628;&#x64A;&#x626;&#x629; &#x627;&#x644;&#x645;&#x62A;&#x635;&#x641;&#x62D; &#x648;&#x627;&#x644;&#x645;&#x648;&#x627;&#x635;&#x641;&#x627;&#x62A; &#x627;&#x644;&#x645;&#x62A;&#x639;&#x644;&#x642;&#x629; &#x628;&#x647;&#x627;</title><link>https://academy.hsoub.com/programming/javascript/%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-%D9%81%D9%8A-%D8%A8%D9%8A%D8%A6%D8%A9-%D8%A7%D9%84%D9%85%D8%AA%D8%B5%D9%81%D8%AD-%D9%88%D8%A7%D9%84%D9%85%D9%88%D8%A7%D8%B5%D9%81%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D8%AA%D8%B9%D9%84%D9%82%D8%A9-%D8%A8%D9%87%D8%A7-r1103/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_01/600d2f3e03017_------.png.fd404a2d7187c5b84dcf1b5d33910801.png" /></p>

<p>
	كانت لغة جافاسكربت عند إنشائها موجّهةً للعمل على متصفّحات الويب، لكنّها تطوّرت مع مرور الوقت وصارت لغة متعدّدة الاستخدامات والمنصّات.
</p>

<p>
	قد تكون المنصّة التي تستضيف جافاسكربت متصفّحا أو خادم ويب أو حتى آلة صنع القهوة، وتوفّر كلّ منها وظائف خاصّة بها. تسمّى هذه المنصّة وفقًا لمواصفة لغة جافاسكربت <em>بالبيئة المضيفة</em> (host environment).
</p>

<p>
	توفّر البيئة المضيفة كائنات ودوالَّ خاصّة بها زيادةً على ما يوجد في اللغة نفسها. فيٌتيح المتصفّح مثلا وسائل للتحكّم في صفحات الويب، وتقدّم Node.js مزايا لإنشاء تطبيقات تعمل في جانب الخادم، إلى غير ذلك.
</p>

<p>
	هذه نظرة عامّة عمّا يكون لدينا عندما تعمل جافاسكربت على متصفّح ويب:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="56325" href="https://academy.hsoub.com/uploads/monthly_2021_01/windowObjects.png.109243c8d01b6374546a5ef5264cca64.png" rel=""><img alt="windowObjects.png" class="ipsImage ipsImage_thumbnailed" data-fileid="56325" data-unique="pb0njmbff" src="https://academy.hsoub.com/uploads/monthly_2021_01/windowObjects.png.109243c8d01b6374546a5ef5264cca64.png"></a>
</p>

<p>
	في أعلى الصّورة كائن "جذر" اسمه <code>window</code> (بمعنى نافذة)، وله دوران:
</p>

<ol>
<li>
		اﻷوّل أنّه كائن عامّ، كما عٌرّف ذلك في مقال <a href="%5Bhttps://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D9%83%D8%A7%D8%A6%D9%86-%D8%A7%D9%84%D8%B9%D9%85%D9%88%D9%85%D9%8A-global-object-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r874/%5D(https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D9%83%D8%A7%D8%A6%D9%86-%D8%A7%D9%84%D8%B9%D9%85%D9%88%D9%85%D9%8A-global-object-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r874/)" rel="">الكائن العامّ</a>.
	</li>
	<li>
		و الثاني أنّه يمثّل "نافذة المتصفّح" ويوفّر توابع للتحكّم فيها.
	</li>
</ol>
<p>
	هذا مثال عن استعماله ككائن عامّ:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2783_7" style="">
<span class="kwd">function</span><span class="pln"> sayHi</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  alert</span><span class="pun">(</span><span class="str">"Hello"</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="com">// الدوالّ العامّة هي توابع للكائن العامّ</span><span class="pln">
window</span><span class="pun">.</span><span class="pln">sayHi</span><span class="pun">();</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="222" loading="lazy" scrolling="no" style="width: 100%;" title="JS-P2-01-browser-environment-ex01" src="https://codepen.io/Hsoub/embed/preview/QWKebEQ?height=222&amp;theme-id=light&amp;default-tab=js,result">See the Pen JS-P2-01-browser-environment-ex01 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	وهذا مثال عن استعماله كنافذة متصفّح، لمعرفة مقدار ارتفاع النافذة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2783_9" style="">
<span class="pln">alert</span><span class="pun">(</span><span class="pln">window</span><span class="pun">.</span><span class="pln">innerHeight</span><span class="pun">);</span><span class="pln"> </span><span class="com">// ارتفاع النافذة الداخلي</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="190" loading="lazy" scrolling="no" src="https://codepen.io/Hsoub/embed/preview/poEMJwO?height=190&amp;theme-id=light&amp;default-tab=js,result" style="width: 100%;" title="JS-P2-01-browser-environment-ex02">See the Pen JS-P2-01-browser-environment-ex02 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	هناك المزيد من الخاصّيّات والتوابع المتعلّقة بكائن <code>window</code>، سنستعرضها لاحقًا.
</p>

<h2>
	نموذج كائن المستند (DOM)
</h2>

<p>
	يمثّل نموذج كائن المستند (Document Object Model أو DOM باختصار) جميع ما تحتويه الصفحة بواسطة كائنات قابلة للتعديل.
</p>

<p>
	يٌعدّ كائن <code>document</code> (أو المستند) "نقطة الدخول" الرئيسية للصفحة، إذ يمكن من خلاله تغيير أو إنشاء أي شيء عليها.
</p>

<p>
	على سبيل المثال:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2783_11" style="">
<span class="com">// جعل الخلفية حمراء اللون </span><span class="pln">
document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">background </span><span class="pun">=</span><span class="pln"> </span><span class="str">"red"</span><span class="pun">;</span><span class="pln">

</span><span class="com">// إرجاعها كما كانت بعد ثانية واحدة</span><span class="pln">
setTimeout</span><span class="pun">(()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">background </span><span class="pun">=</span><span class="pln"> </span><span class="str">""</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1000</span><span class="pun">);</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" src="https://codepen.io/Hsoub/embed/preview/qBaedpd?height=265&amp;theme-id=light&amp;default-tab=js,result" style="width: 100%;" title="JS-p2-01-browser-environment-ex03">See the Pen JS-p2-01-browser-environment-ex03 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	استعملنا هنا خاصيّة <code>document.body.style</code>، غير أنّ هناك المزيد والمزيد من الخاصّيّات والتوابع التي يمكن الاطلاع على جميعها في مواصفة DOM:
</p>

<ul>
<li>
		<strong>DOM Living Standard</strong> على <a href="https://dom.spec.whatwg.org/" ipsnoembed="false" rel="external nofollow">https://dom.spec.whatwg.org/</a>
	</li>
</ul>
<hr>
<p>
	<strong>لا يختص DOM بالمتصفحات</strong>
</p>

<p>
	تبيّن مواصفة DOM بنية المستند وتوفّر كائنات لمعالجته. ويجدر بالذكر أنه يمكن ﻷدواتٍ أخرى غير المتصفّح أن تستخدم DOM.
</p>

<p>
	فعلى سبيل المثال، يمكن لسكربتات جانب الخادم التي تحمّل صفحات HTML وتعالجها أن تستخدم DOM أيضًا، غير أنّها قد لا تدعم إلاّ جزءًا من المواصفة فقط.
</p>

<hr>
<hr>
<p>
	<strong>CSSOM هو للتنسيق</strong>
</p>

<p>
	تٌنظَّم قواعد CSS وصفحات اﻷنماط (stylesheets) تنظيمًا مختلفًا عن تنظيم HTML. لذا فإن لها مواصفة منفصلة، تُسمّى <a href="https://www.w3.org/TR/cssom-1/" rel="external nofollow">نموذج كائن CSS (أو CSSOM اختصارًا لـ CSS Object Model)</a>، تبيّن كيفيّة تمثيلها بكائنات وكذا كيفيّة كتابتها وقرائتها.
</p>

<p>
	يستعمل CSSOM و DOM معًا لتغيير قواعد تنسيق المستند، غير أنّه عمليًّا، قلّ ما يُحتاج إلى CSSOM بحكم أنّ قواعد التنسيق ساكنة في العادة. فبالرغم من أنّه يندر أن يُحتاج لإضافة أو إزالة قواعد CSS من خلال جافاسكربت إلا أنّ ذلك ممكن.
</p>

<hr>
<h2>
	نموذج كائن المتصفح (BOM)
</h2>

<p>
	يمثّل نموذج كائن المتصفّح (Browser Object Model أو BOM باختصار) كائنات أخرى يوفّرها المتصفّح (البيئة المضيفة) للتعامل مع كلّ ما عدا المستند.
</p>

<p>
	على سبيل المثال:
</p>

<ul>
<li>
		<p>
			يعطي كائن <a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/navigator" rel="external nofollow">navigator</a> (بمعنى ملّاح) معلومات أساسيّة عن المتصفّح ونظام التشغيل، وله عدّة خاصّيات لكنّ أشهرها: <code>navigator.userAgent</code> المتعلّقة بالمتصفّح المستخدَم، و <code>navigator.platform</code> المتعلّقة بنظام التشغيل (قد تساعد في التمييز بين ويندوز ولينكس وماك وغيرها).
		</p>
	</li>
	<li>
		<p>
			يمكّن كائن <a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/location" rel="external nofollow">location</a> (بمعنى موقع) من معرفة الرابط (URL) الحاليّ، كما يُمكنه أيضا إعادة توجيه المتصفّح إلى رابط آخر.
		</p>

		<p>
			يمكن مثلا استعمال كائن <code>location</code> كالتالي:
		</p>
	</li>
</ul>
<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2783_13" style="">
<span class="pln">alert</span><span class="pun">(</span><span class="pln">location</span><span class="pun">.</span><span class="pln">href</span><span class="pun">);</span><span class="pln"> </span><span class="com">// عرض الرابط الحالي</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">confirm</span><span class="pun">(</span><span class="str">"هل تودّ زيارة ويكيبيديا؟"</span><span class="pun">))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  location</span><span class="pun">.</span><span class="pln">href </span><span class="pun">=</span><span class="pln"> </span><span class="str">"https://wikipedia.org"</span><span class="pun">;</span><span class="pln"> </span><span class="com">// إعادة توجيه المتصفّح لرابط آخر</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	<iframe allowfullscreen="true" allowtransparency="true" frameborder="no" height="265" loading="lazy" scrolling="no" src="https://codepen.io/Hsoub/embed/preview/NWRQqyM?height=265&amp;theme-id=light&amp;default-tab=js,result" style="width: 100%;" title="JS-p2-01-browser-environment-ex04">See the Pen JS-p2-01-browser-environment-ex04 by Hsoub (@Hsoub) on CodePen.</iframe>
</p>

<p>
	تُعدّ كلٌّ من دوالّ <code>alert</code> و <code>confirm</code> و <code>prompt</code> كذلك جزءا من BOM، فهي لا تتعلّق بالمستند تعلّقًا مباشرًا، بل تمثّل توابع متصفّح خالصة للتواصل مع المستخدم.
</p>

<hr>
<p>
	<strong>عن المواصفات</strong>
</p>

<p>
	يعدّ BOM جزءا من <a href="https://html.spec.whatwg.org/" rel="external nofollow">مواصفة HTML</a> العامّة. نعم، لم تتوهّم سماع ذلك. لا تقتصر مواصفة HTML على "لغة HTML" (من وسوم وسمات)، بل تشمل كذلك عدّة كائنات و توابع وامتدادات DOM خاصّة بالمتصفّح، وهو " HTML بمعناه العامّ". كما أنّ لبعض اﻷجزاء الأخرى مواصفات مستقلّة كذلك وهي مدرجة هنا <a href="https://spec.whatwg.org/" rel="external nofollow">https://spec.whatwg.org</a>.
</p>

<hr>
<h2>
	الخلاصة
</h2>

<p>
	بالحديث عن المعايير، يمكن الخلوص إلى ما يلي:
</p>

<ul>
<li>
		<p>
			مواصفة DOM: تبيّن بنية المستند، وطرق معالجته، وما يتعلّق بالأحداث (events). للاطلاع عليها <a href="https://dom.spec.whatwg.org/." ipsnoembed="false" rel="external nofollow">https://dom.spec.whatwg.org/.</a>
		</p>
	</li>
	<li>
		<p>
			مواصفة CSSOM: تبيّن صفحات اﻷنماط وقواعد التنسيق، و كيفيّة استخدامها للمعالجة، وكذا ارتباطها بالمستند. للاطلاع عليها <a href="https://www.w3.org/TR/cssom-1/." ipsnoembed="false" rel="external nofollow">https://www.w3.org/TR/cssom-1/.</a>
		</p>
	</li>
	<li>
		<p>
			مواصفة HTML: تبيّن لغة HTML (كالوسوم مثلا)، كما تبيّن نموذج كائن المتصفّح BOM وما يوفّره من مختلف الدوالّ مثل <code>setTimeout</code> و <code>alert</code> و <code>location</code> وغيرها. تعدّ هذه المواصفة توسعة لمواصفة DOM بمزيد من الخاصيّات والتوابع. للاطلاع عليها <a href="https://html.spec.whatwg.org." ipsnoembed="false" rel="external nofollow">https://html.spec.whatwg.org.</a>
		</p>
	</li>
</ul>
<p>
	إضافة لما سبق، بعض اﻷصناف لها مواصفاتً مستقلّة تُبيّنها. للاطلاع عليها <a href="https://spec.whatwg.org." ipsnoembed="false" rel="external nofollow">https://spec.whatwg.org.</a>
</p>

<p>
	يُرجى الاعتناء بهذه الروابط، إذ هناك الكثير من اﻷمور لتعلمّها، ويستحيل الوقوف عند جميعها فضلا عن حفظها.
</p>

<p>
	لدراسة خاصّية أو تابع ما، يعدّ دليل موزيلا <a href="https://developer.mozilla.org/ar/docs/Learn" ipsnoembed="false" rel="external nofollow">https://developer.mozilla.org/ar/docs/Learn</a> من أحسن المصادر لذلك، لكن قراءة المواصفة أفضل رغم تعقيدها وطولها، إذ من شأنها أن تورث معرفة تامّة وسليمة.
</p>

<p>
	لإيجاد شيء ما، يُستحسن البحث في الانترنت على النّحو التالي: "[مصطلح البحث] WHATWG" أو "[مصطلح البحث] MDN" ،على سبيل المثال: <a href="https://google.com/?q=whatwg+localstorage" rel="external nofollow">https://google.com?q=whatwg+localstorage</a> ،<a href="https://google.com/?q=mdn+localstorage" rel="external nofollow">https://google.com?q=mdn+localstorage</a>.
</p>

<p>
	في ما يلي، سنشرع في تعلّم DOM، فللصفحة (أي document) دور محوري في واجهة المستخدم.
</p>

<p>
	ترجمة -وبتصرف- للفصل <a href="https://javascript.info/browser-environment" rel="external nofollow">Browser environment, specs</a> من كتاب <a href="https://javascript.info/ui" rel="external nofollow">Browser: Document, Events, Interfaces</a>
</p>
]]></description><guid isPermaLink="false">1103</guid><pubDate>Mon, 11 Jan 2021 13:00:00 +0000</pubDate></item><item><title>&#x634;&#x631;&#x62D; &#x627;&#x644;&#x646;&#x648;&#x639; &#x627;&#x644;&#x645;&#x631;&#x62C;&#x639;&#x64A; (Reference Type) &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A;</title><link>https://academy.hsoub.com/programming/javascript/%D8%B4%D8%B1%D8%AD-%D8%A7%D9%84%D9%86%D9%88%D8%B9-%D8%A7%D9%84%D9%85%D8%B1%D8%AC%D8%B9%D9%8A-reference-type-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r1008/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_09/Reference-Type.png.2ea570274565eac7e53868c5e285e773.png" /></p>

<p>
	<strong>ملاحظة مهمة</strong>: هذه الشرح لميزات اللغة المتقدمة، إذ تتناول هذه المقالة موضوعًا متقدمًا، لفهم بعض الحالات الهامشية بطريقة أفضل. مع العلم أنها ليست مهمة. والعديد من المطورين ذوي الخبرة الجيدة ينفذون مشاريعهم بدون معرفتها. ولكن إذا أردت معرفة كيفية عمل الأشياء تحت الطاولة فتابع القراءة.
</p>

<p>
	إن استدعاء التابع المقيم ديناميكيًا يمكن أن يفقد قيمة <code>this</code>.
</p>

<p>
	فمثلًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7735_7" style="">
<span class="pln">let user </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"John"</span><span class="pun">,</span><span class="pln">
  hi</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> alert</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">name</span><span class="pun">);</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
  bye</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> alert</span><span class="pun">(</span><span class="str">"Bye"</span><span class="pun">);</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

user</span><span class="pun">.</span><span class="pln">hi</span><span class="pun">();</span><span class="pln"> </span><span class="com">// works</span><span class="pln">

</span><span class="com">// لنستدعي الآن ‫user.hi أو user.bye بحسب الاسم</span><span class="pln">
_</span><span class="pun">(</span><span class="pln">user</span><span class="pun">.</span><span class="pln">name </span><span class="pun">==</span><span class="pln"> </span><span class="str">"John"</span><span class="pln"> </span><span class="pun">?</span><span class="pln"> user</span><span class="pun">.</span><span class="pln">hi </span><span class="pun">:</span><span class="pln"> user</span><span class="pun">.</span><span class="pln">bye</span><span class="pun">)();</span><span class="pln"> </span><span class="com">// خطأ</span></pre>

<p>
	يوجد في السطر الأخير معامل شرطي يختار إما <code>user.hi</code> أو <code>user.bye</code>. في هذه الحالة تكون النتيجة <code>user.hi</code>.
</p>

<p>
	ثم تستدعى الدالّة ذات الأقواس <code>()</code> على الفور لكنها لن تعمل بطريقة صحيحة!
</p>

<p>
	كما تلاحظ، نتج عن الاستدعاء بالطريقة السابقة خطأ، وذلك لأن قيمة <code>this</code> داخل الاستدعاء تصبح غير معرفة <code>undefined</code>.
</p>

<p>
	نلاحظ هنا أن هذه الطريقة تعمل بصورة صحيحة (اسم الكائن ثم نقطة ثم اسم الدالّة):
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7735_9" style="">
<span class="pln">user</span><span class="pun">.</span><span class="pln">hi</span><span class="pun">();</span></pre>

<p>
	أما هذه الطريقة فلن تعمل (طريقة تقييم الدالّة):
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7735_11" style="">
<span class="pun">(</span><span class="pln">user</span><span class="pun">.</span><span class="pln">name </span><span class="pun">==</span><span class="pln"> </span><span class="str">"John"</span><span class="pln"> </span><span class="pun">?</span><span class="pln"> user</span><span class="pun">.</span><span class="pln">hi </span><span class="pun">:</span><span class="pln"> user</span><span class="pun">.</span><span class="pln">bye</span><span class="pun">)();</span><span class="pln"> </span><span class="com">// Error!</span></pre>

<p>
	لماذا حدث ذلك؟ إذا أردنا أن نفهم سبب حدوث ذلك، فلنتعرف أولًا على كيفية عمل الاستدعاء <code>obj.method()‎</code>.
</p>

<h2>
	شرح النوع المرجعي
</h2>

<p>
	بالنظر عن كثب، قد نلاحظ عمليتين في العبارة <code>obj.method()‎</code>:
</p>

<ol>
<li>
		أولًا، تسترجع النقطة <code>'.'</code> الخاصية <code>obj.method</code>.
	</li>
	<li>
		ثم تأتي الأقواس <code>()</code> لتنفّذها.
	</li>
</ol>
<p>
	إذًا كيف تنتقل المعلومات الخاصة بقيمة <code>this</code> من الجزء الأول إلى الجزء الثاني؟
</p>

<p>
	إذا وضعنا هذه العمليات في سطور منفصلة، فسنفقدُ قيمة <code>this</code> بكل تأكيد:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7735_13" style="">
<span class="pln">let user </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"John"</span><span class="pun">,</span><span class="pln">
  hi</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> alert</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">name</span><span class="pun">);</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="com">// جزّء استدعاء التوابع على سطرين</span><span class="pln">
let hi </span><span class="pun">=</span><span class="pln"> user</span><span class="pun">.</span><span class="pln">hi</span><span class="pun">;</span><span class="pln">
hi</span><span class="pun">();</span><span class="pln"> </span><span class="com">// خطأ لأنها غير معرّفة</span></pre>

<p>
	إن التعليمة <code>hi = user.hi</code> تضع الدالّة في المتغير، ثم الاستدعاء في السطر الأخير يكون مستقلًا تمامًا، وبالتالي لا يوجد قيمة لـ <code>this</code>.
</p>

<p>
	لجعل استدعاءات <code>user.hi()‎</code> تعمل بصورة صحيحة، تستخدم لغة جافاسكربت خدعة - بأن لا تُرجع النقطة <code>'.'</code> دالة، وإنما قيمة من <a href="https://tc39.github.io/ecma262/#sec-reference-specification-type" rel="external nofollow">نوع مرجعي</a>.
</p>

<p>
	إن <strong>القيمة من نوع مرجعي</strong> هو "نوع من المواصفات". لا يمكننا استخدامها بطريقة مباشرة، ولكن تستخدم داخليًا بواسطة اللغة.
</p>

<p>
	إن القيمة من نوع مرجعي هي مجموعة من ثلاث قيم <code>(base, name, strict)</code>، ويشير كلُّ منها إلى:
</p>

<ul>
<li>
		<code>base</code>: وهو الكائن.
	</li>
	<li>
		<code>name</code> وهو اسم الخاصية.
	</li>
	<li>
		<code>strict</code> تكون قيمتها <code>true</code> إذا كان الوضع الصارم مفعلًا.
	</li>
</ul>
<p>
	إن نتيجة وصول الخاصية <code>user.hi</code> ليست دالة، ولكنها قيمة من نوع مرجعي. بالنسبة إلى <code>user.hi</code> في الوضع الصارم، تكون هكذا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7735_15" style="">
<span class="com">// قيمة من نوع مرجعي</span><span class="pln">
</span><span class="pun">(</span><span class="pln">user</span><span class="pun">,</span><span class="pln"> </span><span class="str">"hi"</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">)</span></pre>

<p>
	عندما تستدعى الأقواس <code>()</code> في النوع المرجعي، فإنها تتلقى المعلومات الكاملة حول الكائن ودواله، ويمكنهم تعيين قيمة <code>this</code> (ستكون user في حالتنا).
</p>

<p>
	النوع المرجعي هو نوع داخلي خاص "وسيط"، بهدف تمرير المعلومات من النقطة <code>.</code> إلى أقواس الاستدعاء <code>()</code>.
</p>

<p>
	أي عملية أخرى مثل الإسناد <code>hi = user.hi</code> تتجاهل نوع المرجع ككلّ، وتأخذ قيمة <code>user.hi</code> (كدالّة) وتمررها. لذا فإن أي عملية أخرى تفقد قيمة <code>this</code>.
</p>

<p>
	لذلك وكنتيجة لما سبق، تُمرر قيمة <code>this</code> بالطريقة الصحيحة فقط إذا استدعيت الدالّة مباشرة باستخدام نقطة <code>obj.method()‎</code> أو الأقواس المربعة <code>obj['method']()‎</code> (الصياغتين تؤديان الشيء نفسه). لاحقًا في هذا السلسلة التعليمية، سنتعلم طرقًا مختلفة لحل هذه المشكلة مثل الدالّة <a href="https://javascript.info/bind#solution-2-bind" rel="external nofollow">func.bind()</a><code>‎</code>.
</p>

<h2>
	الخلاصة
</h2>

<p>
	النوع المرجعي هو نوع داخلي في لغة جافاسكربت. فقراءة خاصية ما، مثل النقطة <code>.</code> في<code>obj.method()‎</code> لا تُرجع قيمة الخاصية فحسب، بل تُرجع قيمة من "نوع مرجعي" خاص والّتي تخزن فيها قيمة الخاصية والكائن المأخوذة منه. هذه طريقة لاستدعاء الدالة اللاحقة <code>()</code> للحصول على الكائن وتعيين قيمة <code>this</code> إليه.
</p>

<p>
	بالنسبة لجميع العمليات الأخرى، يصبح قيمة النوع المرجعي تلقائيًا قيمة الخاصية (الدالّة في حالتنا). جميع هذه الآليات مخفية عن أعيننا. ولا تهمنا إلا في الحالات الدقيقة، مثل عندما نريد الحصول على تابع ديناميكيًا من الكائن ما، باستخدام تعبير معيّن.
</p>

<h2>
	المهام
</h2>

<h3>
	التحقق من الصياغة
</h3>

<p>
	<em>الأهمية: 2</em>
</p>

<p>
	ما هي نتيجة هذه الشيفرة البرمجية؟
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7735_17" style="">
<span class="pln">let user </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"John"</span><span class="pun">,</span><span class="pln">
  go</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> alert</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">name</span><span class="pun">)</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="pun">(</span><span class="pln">user</span><span class="pun">.</span><span class="pln">go</span><span class="pun">)()</span></pre>

<p>
	انتبه. هنالك فخ <img alt=":)" data-emoticon="true" height="20" src="https://academy.hsoub.com/uploads/monthly_2015_02/smile.png.cf72ab87c1aaefd42371e0a7de39cfae.png" srcset="https://academy.hsoub.com/uploads/emoticons/smile@2x.png 2x" title=":)" width="20"></p>
<style type="text/css">
.anntional__paragraph {
    border: 3px solid #f5f5f5;
    margin: 20px 0 14px;
    position: relative;
    display: block;
    padding: 25px 30px;
}</style>
<div class="anntional__paragraph">
	<p>
		<strong>الحل</strong>
	</p>

	<p>
		سينتج عن تنفيذ الشيفرة السابقة <strong>خطأ</strong>!
	</p>

	<p>
		جربها بنفسك:
	</p>

	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7735_19" style="">
<span class="pln">let user </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"John"</span><span class="pun">,</span><span class="pln">
  go</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> alert</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">name</span><span class="pun">)</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="pun">(</span><span class="pln">user</span><span class="pun">.</span><span class="pln">go</span><span class="pun">)()</span><span class="pln"> </span><span class="com">// error!</span></pre>

	<p>
		لا تعطينا رسالة الخطأ في معظم المتصفحات فكرة عن الخطأ الّذي حدث.
	</p>

	<p>
		<strong>يظهر الخطأ بسبب فقدان فاصلة منقوطة بعد <code>user = {...}‎</code>.</strong>
	</p>

	<p>
		إذ لا تُدرج لغة جافاسكربت تلقائيًا فاصلة منقوطة قبل قوس <code>‎(user.go)()‎</code>، لذلك تُقرأ الشيفرة البرمجية هكذا:
	</p>

	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7735_23" style="">
<span class="pln">let user </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> go</span><span class="pun">:...</span><span class="pln"> </span><span class="pun">}(</span><span class="pln">user</span><span class="pun">.</span><span class="pln">go</span><span class="pun">)()</span></pre>

	<p>
		ثم يمكننا أن نرى أيضًا أن مثل هذا التعبير المشترك هو من الناحية التركيبية استدعاء للكائن <code>‎{ go: ... }‎</code> كدالة مع الوسيط <code>(user.go)</code>. ويحدث ذلك أيضًا على نفس السطر مع <code>let user</code>، لذلك إن الكائن <code>user</code> لم يُعرّف حتى الآن، ومن هنا ظهر الخطأ.
	</p>

	<p>
		إذا أدخلنا الفاصلة المنقوطة، فسيكون كل شيء على ما يرام:
	</p>

	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7735_25" style="">
<span class="pln">let user </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"John"</span><span class="pun">,</span><span class="pln">
  go</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> alert</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">name</span><span class="pun">)</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

</span><span class="pun">(</span><span class="pln">user</span><span class="pun">.</span><span class="pln">go</span><span class="pun">)()</span><span class="pln"> </span><span class="com">// John</span></pre>

	<p>
		يرجى ملاحظة أن الأقواس حول <code>(user.go)</code> لا تفعل شيئًا مميزًا هنا. وهي عادةً تعيد ترتيب العمليات، ولكن هنا تعمل النقطة <code>.</code> أولًا على أي حال، لذلك ليس هناك أي تأثير لها. الشيء الوحيد المهم هو الفاصلة المنقوطة.
	</p>
</div>

<h3>
	اشرح قيمة <code>this</code>
</h3>

<p>
	<em>الأهمية: 3</em>
</p>

<p>
	في الشيفرة أدناه، نعتزم استدعاء التابع <code>obj.go()‎</code> لأربع مرات على متتالية.
</p>

<p>
	ولكن لماذا الندائين <code>(1)</code> و<code>(2)</code> يعملان بطريقة مختلفة عن الندائين <code>(3)</code> و<code>(4)</code>؟
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7735_27" style="">
<span class="pln">let obj</span><span class="pun">,</span><span class="pln"> method</span><span class="pun">;</span><span class="pln">

obj </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  go</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> alert</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">);</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

obj</span><span class="pun">.</span><span class="pln">go</span><span class="pun">();</span><span class="pln">               </span><span class="com">// (1) [object Object]</span><span class="pln">

</span><span class="pun">(</span><span class="pln">obj</span><span class="pun">.</span><span class="pln">go</span><span class="pun">)();</span><span class="pln">             </span><span class="com">// (2) [object Object]</span><span class="pln">

</span><span class="pun">(</span><span class="pln">method </span><span class="pun">=</span><span class="pln"> obj</span><span class="pun">.</span><span class="pln">go</span><span class="pun">)();</span><span class="pln">    </span><span class="com">// (3) undefined</span><span class="pln">

</span><span class="pun">(</span><span class="pln">obj</span><span class="pun">.</span><span class="pln">go </span><span class="pun">||</span><span class="pln"> obj</span><span class="pun">.</span><span class="pln">stop</span><span class="pun">)();</span><span class="pln"> </span><span class="com">// (4) undefined</span></pre>

<div class="anntional__paragraph">
	<p>
		<strong>الحل</strong>
	</p>

	<p>
		إليك تفسير ما حدث.
	</p>

	<ol>
<li>
			<p>
				هذا هو الطريقة العادية لاستدعاء تابع الكائن.
			</p>
		</li>
		<li>
			<p>
				نفس الأمر يتكرر هنا، الأقواس لا تغير ترتيب العمليات هنا، النقطة هي الأولى على أي حال.
			</p>
		</li>
		<li>
			<p>
				هنا لدينا استدعاء أكثر تعقيدًا <code>‎(expression).method()‎</code>. يعمل الاستدعاء كما لو كانت مقسمة على سطرين:
			</p>

			<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7735_29" style="">
<span class="pln">f </span><span class="pun">=</span><span class="pln"> obj</span><span class="pun">.</span><span class="pln">go</span><span class="pun">;</span><span class="pln"> </span><span class="com">// يحسب نتيجة التعبير</span><span class="pln">
f</span><span class="pun">();</span><span class="pln">        </span><span class="com">// يستدعي ما لدينا</span></pre>

			<p>
				هنا تُنفذ <code>f()‎</code> كدالة، بدون <code>this</code>.
			</p>
		</li>
		<li>
			<p>
				مثل ما حدث مع الحالة <code>(3)</code> على يسار النقطة <code>.</code> لدينا تعبير.
			</p>
		</li>
	</ol>
<p>
		لشرح سلوك <code>(3)</code> و<code>(4)</code> نحتاج إلى أن نتذكر أن توابع الوصول (accessors) للخاصيات (النقطة أو الأقواس المربعة) تُعيد قيمة النوع المرجعي.
	</p>

	<p>
		أي عملية نطبقها عليها باستثناء استدعاء التابع (مثل عملية الإسناد <code>=</code> أو <code>||</code>) تحولها إلى قيمة عادية، والّتي لا تحمل المعلومات التي تسمح لها بتعيين قيمة <code>this</code>.
	</p>
</div>

<p>
	ترجمة -وبتصرف- للفصل <a href="https://javascript.info/reference-type" rel="external nofollow">Reference Type</a> من كتاب <a href="https://javascript.info/js" rel="external nofollow">The JavaScript language</a>
</p>
]]></description><guid isPermaLink="false">1008</guid><pubDate>Sat, 19 Sep 2020 07:31:28 +0000</pubDate></item><item><title>&#x627;&#x644;&#x62A;&#x633;&#x644;&#x633;&#x644; &#x627;&#x644;&#x627;&#x62E;&#x62A;&#x64A;&#x627;&#x631;&#x64A; ".?" &#x644;&#x644;&#x648;&#x635;&#x648;&#x644; &#x644;&#x62E;&#x627;&#x635;&#x64A;&#x627;&#x62A; &#x643;&#x627;&#x626;&#x646; &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A;</title><link>https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%AA%D8%B3%D9%84%D8%B3%D9%84-%D8%A7%D9%84%D8%A7%D8%AE%D8%AA%D9%8A%D8%A7%D8%B1%D9%8A-%D9%84%D9%84%D9%88%D8%B5%D9%88%D9%84-%D9%84%D8%AE%D8%A7%D8%B5%D9%8A%D8%A7%D8%AA-%D9%83%D8%A7%D8%A6%D9%86-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r1007/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_09/Optional-chaining.png.091e5eccb8a1bc35c4e31d8ef69f7d5c.png" /></p>

<p>
	<strong>ملاحظة مهمة</strong>: هذه إضافة حديثة للغة، لذا قد تحتاج المتصفحات القديمة لترقيع هذا النقص.
</p>

<p>
	<strong>التسلسل الاختياري</strong> <code>.?</code> هو طريقة مقاومة للأخطاء للوصول إلى خصائص الكائن المتداخلة، حتى إذا كانت الخاصية الوسيطة غير موجودة.
</p>

<h2>
	المشكلة
</h2>

<p>
	إذا كنت قد بدأت للتو في قراءة هذه السلسلة التعليمية وتتعلم جافاسكربت، فلربما لم تواجه هذه المشكلة بعد، لكنها شائعة جدًا.
</p>

<p>
	فمثلًا، يمتلك بعض من المستخدمين لدينا يمتلكون عناوين، لكن هنالك قليل منهم لم يقدمها. لذا لا يمكننا قراءة <code>user.address.street</code> بأمان. هكذا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2537_7" style="">
<span class="pln">let user </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{};</span><span class="pln"> </span><span class="com">// تحدث للمستخدم ‫user في حالة كان ليس لديه عنوان</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln">user</span><span class="pun">.</span><span class="pln">address</span><span class="pun">.</span><span class="pln">street</span><span class="pun">);</span><span class="pln"> </span><span class="com">// خطأ!‫  </span></pre>

<p>
	أو عند تطويرنا لموقع وِب، ونرغب في الحصول على معلومات حول عنصر ما في الصفحة، لكنه قد لا يكون موجودًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2537_9" style="">
<span class="com">// إذا كان نتيجة ‫querySelector(...)‎ فارغًا</span><span class="pln">
let html </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">'.my-element'</span><span class="pun">).</span><span class="pln">innerHTML</span><span class="pun">;</span></pre>

<p>
	قبل ظهور "‎?.‎" في اللغة، كان يستخدم المعامل <code>&amp;&amp;</code> للتغلب على المشكلة.
</p>

<p>
	فمثلًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2537_11" style="">
<span class="pln">let user </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{};</span><span class="pln"> </span><span class="com">// إذا كان ‫user لا يملك عنوان</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> user </span><span class="pun">&amp;&amp;</span><span class="pln"> user</span><span class="pun">.</span><span class="pln">address </span><span class="pun">&amp;&amp;</span><span class="pln"> user</span><span class="pun">.</span><span class="pln">address</span><span class="pun">.</span><span class="pln">street </span><span class="pun">);</span><span class="pln"> </span><span class="com">// undefined (أي ليس خطأً)</span></pre>

<p>
	وكونها تتطلب كتابة طويلة للتأكد من وجود جميع المكونات، لذلك كان استخدامها مرهقًا.
</p>

<h2>
	تسلسل اختياري
</h2>

<p>
	التسلسل الاختياري "‎?.‎" يوقف التقييم ويعيد غير معرّف <code>undefined</code> إذا كان الجزء قبل "‎?.‎" غير معرّف <code>undefined</code> أو فارغ <code>null</code>.
</p>

<p>
	**للإيجاز سنفترض في هذه المقالة أن شيئًا ما "موجود" إذا لم تكن القيمة "فارغة" <code>null</code> أو غير معرّفة <code>undefined</code>. **
</p>

<p>
	إليك الطريقة الآمنة للوصول إلى <code>user.address.street</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2537_13" style="">
<span class="pln">let user </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{};</span><span class="pln"> </span><span class="com">// إذا كان ‫user لا يملك عنوان</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> user</span><span class="pun">?.</span><span class="pln">address</span><span class="pun">?.</span><span class="pln">street </span><span class="pun">);</span><span class="pln"> </span><span class="com">// undefined (ليس خطأً)</span></pre>

<p>
	إن قراءة العنوان باستخدام هذه الطريقة <code>user?.address</code> ستعمل حتى ولو كان الكائن <code>user</code> غير موجود:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2537_15" style="">
<span class="pln">let user </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">;</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> user</span><span class="pun">?.</span><span class="pln">address </span><span class="pun">);</span><span class="pln"> </span><span class="com">// undefined</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> user</span><span class="pun">?.</span><span class="pln">address</span><span class="pun">.</span><span class="pln">street </span><span class="pun">);</span><span class="pln"> </span><span class="com">// undefined</span></pre>

<p>
	الرجاء ملاحظة أن: صياغة جملة <code>.?</code> تجعل القيمة الموجودة قبلها اختيارية، ولكن ليس القيمة الّتي تأتي بعدها.
</p>

<p>
	في المثال أعلاه، تسمح التعليمة "user?.‎" للكائن <code>user</code> فقط بأن يكون غير معرف أو فارغ "null/undefined". من ناحية أخرى، إذا كان الكائن <code>user</code> موجودًا، فيجب أن يحتوي على خاصية <code>user.address</code>، وإلا فإن <code>user?.address.street</code> ستُعطي خطأ في النقطة الثانية.
</p>

<p>
	<strong>ملاحظة</strong>: لا تفرط في استخدام التسلسل الاختياري. يجب أن نستخدم <code>.?</code> فقط في حالة عدم وجود شيئ ما.
</p>

<p>
	فمثلًا، بحسب منطق الشيفرة خاصتنا يجب أن يكون الكائن <code>user</code> موجودًا، ولكن الخاصية <code>address</code> اختيارية، بهذه الحالة سيكون <code>user?.address.street</code> أفضل. لذلك، إذا حدث أن كان الكائن <code>user</code> غير معرف بسبب خطأ ما، فسنُعرف عنه ونصلحه. خلاف ذلك، يمكن إسكات أخطاء الترميز عندما لا يكون ذلك مناسبًا، ويصبح تصحيحها أكثر صعوبة.
</p>

<p>
	<strong>ملاحظة</strong>: يجب التصريح عن المتغير الموجود قبل <code>.?</code>
</p>

<p>
	إذا لم يكن هناك متغير <code>user</code> على الإطلاق، فإن التعليمة <code>user?.anything</code> ستؤدي حتمًا إلى حدوث خطأ:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2537_17" style="">
<span class="com">// ReferenceError: إن المستخدم ‫user غير معرًف</span><span class="pln">
user</span><span class="pun">?.</span><span class="pln">address</span><span class="pun">;</span></pre>

<p>
	يجب أن يكون هناك تعريف واضح للمتغير <code>let / const / var user</code>. لأن التسلسل الاختياري يعمل فقط للمتغيرات المصرح عنها.
</p>

<h2>
	اختيار الطريق الأقصر
</h2>

<p>
	كما قلنا سابقًا، ستوقف <code>.?</code> فورًا (أي سيحدث قصر في الدارة) إذا لم يكن الجزء الأيسر موجودًا.
</p>

<p>
	لذلك، إذا كان هناك أي استدعاءات دوالّ أخرى أو آثار جانبية، فلن تحدث:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2537_19" style="">
<span class="pln">let user </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">;</span><span class="pln">
let x </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">

user</span><span class="pun">?.</span><span class="pln">sayHi</span><span class="pun">(</span><span class="pln">x</span><span class="pun">++);</span><span class="pln"> </span><span class="com">// لا يحدث شيئ</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln">x</span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫0, لم تزداد القيمة</span></pre>

<h2>
	حالات أخرى ()?. و []?.
</h2>

<p>
	إن التسلسل الاختياري <code>‎.?</code> ليس مُعامل، ولكنه طريقة معينة لصياغة تعليمة، يعمل أيضًا مع الدوالّ والأقواس المربعة.
</p>

<p>
	فمثلًا، تُستخدم <code>().?</code> لاستدعاء دالّة قد لا تكون موجودة.
</p>

<p>
	نلاحظ في الشيفرة أدناه، أنه لدى بعض مستخدمينا التابع <code>admin</code> والبعض ليس لديه:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2537_21" style="">
<span class="pln">let user1 </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  admin</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    alert</span><span class="pun">(</span><span class="str">"I am admin"</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

let user2 </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{};</span><span class="pln">

user1</span><span class="pun">.</span><span class="pln">admin</span><span class="pun">?.();</span><span class="pln"> </span><span class="com">// I am admin</span><span class="pln">
user2</span><span class="pun">.</span><span class="pln">admin</span><span class="pun">?.();</span></pre>

<p>
	هنا، في كلا السطرين، نستخدم النقطة <code>.</code> أولًا للحصول على خاصية <code>admin</code>، لأن كائن المستخدم <code>user</code> يجب أن يكون موجودًا، لذا فهو آمن للقراءة منه. ثم يتحقق <code>().?</code> من الجزء الأيسر: إذا كانت دالّة المسؤول موجودة، فستنفذ (على الكائن <code>user1</code>). وبخلاف ذلك (بالنسبة للكائن <code>user2</code>) يتوقف التقييم الشيفرة بدون أخطاء.
</p>

<p>
	تعمل الصياغة <code>[].?</code> أيضًا، إذا أردنا استخدام الأقواس <code>[]</code> للوصول إلى الخصائص بدلًا من النقطة <code>.</code>. على غرار الحالات السابقة، فإنه يسمح بقراءة خاصية بأمان من كائن قد لا يكون موجودًا.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2537_23" style="">
<span class="pln">let user1 </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  firstName</span><span class="pun">:</span><span class="pln"> </span><span class="str">"John"</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

let user2 </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">;</span><span class="pln"> </span><span class="com">// Imagine, we couldn't authorize the user</span><span class="pln">

let key </span><span class="pun">=</span><span class="pln"> </span><span class="str">"firstName"</span><span class="pun">;</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> user1</span><span class="pun">?.[</span><span class="pln">key</span><span class="pun">]</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// John</span><span class="pln">
alert</span><span class="pun">(</span><span class="pln"> user2</span><span class="pun">?.[</span><span class="pln">key</span><span class="pun">]</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> </span><span class="com">// undefined</span><span class="pln">

alert</span><span class="pun">(</span><span class="pln"> user1</span><span class="pun">?.[</span><span class="pln">key</span><span class="pun">]?.</span><span class="pln">something</span><span class="pun">?.</span><span class="pln">not</span><span class="pun">?.</span><span class="pln">existing</span><span class="pun">);</span><span class="pln"> </span><span class="com">// undefined</span></pre>

<p>
	كما يمكننا استخدام <code>.?</code> مع <code>delete</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2537_25" style="">
<span class="kwd">delete</span><span class="pln"> user</span><span class="pun">?.</span><span class="pln">name</span><span class="pun">;</span><span class="pln"> </span><span class="com">// احذف المستخدم ‫user.name إذا كان موجودًا</span></pre>

<p>
	<strong>ملاحظة</strong>: يمكننا استخدام <code>.?</code> للقراءة الآمنة والحذف، ولكن ليس الكتابة
</p>

<p>
	التسلسل الاختياري <code>.?</code> ليس له أي فائدة في الجانب الأيسر من المهمة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2537_27" style="">
<span class="com">// فكرة الشيفرة أدناه أن تكتب قيمة ‫user.name إذا لم تكن موجودة</span><span class="pln">

user</span><span class="pun">?.</span><span class="pln">name </span><span class="pun">=</span><span class="pln"> </span><span class="str">"John"</span><span class="pun">;</span><span class="pln"> </span><span class="com">// خطأ لن تعمل الشيفرة</span><span class="pln">
</span><span class="com">// لأن الإسناد بين ‫undefined = "John"‎</span></pre>

<h2>
	الخلاصة
</h2>

<p>
	يتكون بناء جملة التسلسل الاختياري <code>.?</code> من ثلاثة أشكال:
</p>

<ol>
<li>
		<code>obj?.prop</code> - ستُعيد <code>obj.prop</code> إذا كان الكائن <code>obj</code> موجودًا، وإلا ستعيد القيمة <code>undefined</code>.
	</li>
	<li>
		<code>obj?.[prop]‎</code> - ستُعيد <code>obj[prop]‎</code> إذا كان الكائن <code>obj</code> موجودًا، وإلا ستُعيد <code>undefined</code>.
	</li>
	<li>
		<code>obj?.method()‎</code> - تستدعي <code>obj.method()‎</code> إذا كان الكائن <code>obj</code> موجودًا، وإلا ستُعيد <code>undefined</code>.
	</li>
</ol>
<p>
	كما رأينا كل الطرق واضحة وسهلة الاستخدام. تتحقق <code>.?</code> من الجزء الأيسر بحثًا عن قيمة فارغة أو غير معرفة <code>null/undefined</code> ويسمح للتقييم بالمتابعة إذا لم يكن كذلك.
</p>

<p>
	تسمح سلسلة <code>.?</code> بالوصول الآمن إلى الخصائص المتداخلة. ومع ذلك، يجب أن نطبق <code>.?</code> بحذر، وفقط في الحالات الّتي يكون فيها الجزء الأيسر غير موجود، حتى لا نخفي عن أنفسنا الأخطاء البرمجية إذا حدثت.
</p>

<p>
	ترجمة -وبتصرف- للفصل <a href="https://javascript.info/optional-chaining" rel="external nofollow">Optional chaining '?.'</a> من كتاب <a href="https://javascript.info/js" rel="external nofollow">The JavaScript language</a>
</p>
]]></description><guid isPermaLink="false">1007</guid><pubDate>Sat, 19 Sep 2020 07:03:44 +0000</pubDate></item></channel></rss>
