# محتويات بطاقة المستخدم المثبتة - السمة

**URL:** <https://meta.discourse.org/t/sticky-user-card-contents-theme/159875>\
**Category:** Development\
**Created:** [5 أغسطس 2020، 9:13ص UTC](https://meta.discourse.org/t/sticky-user-card-contents-theme/159875 "2020-08-05T09:13:23Z")\
**Posts on this page:** 1\
**Showing post:** 4

<div class="post-metadata">

**Author:** ![Johani](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/johani/32/176920_2.png) [@Johani](https://meta.discourse.org/u/Johani)\
**Post date:** [7 أغسطس 2020، 11:57ص UTC](https://meta.discourse.org/t/sticky-user-card-contents-theme/159875/4 "2020-08-07T11:57:06Z")

</div>

TL;DR أعتقد أن هذا ما تبحث عنه

Theme JS

```javascript
api.modifyClass("component:user-card-contents", {
  didInsertElement() {
    this._super(...arguments);
    $("html").off(this.clickOutsideEventName);
  },
  actions: {
    closeCard() {
      this._close();
    }
  }
});

```

ثم أضف هذا إلى قالبك في مكان ما

```plaintext
{{d-button
  class="btn-flat"
  action=(action "closeCard")
  icon="times"
}}

```

**النسخة الطويلة**

ربما كنت تعرف معظم هذا بالفعل لأنك عملت بالفعل على سمة (Theme) الخاصة بك، لكنني سأحاول أن أجعلها أكثر تفصيلاً قليلاً للجمهور الأوسع.

> [@sonicb](#):
>
> clickOutsideEventName

أول شيء سأفعله هو البحث إما محليًا أو على Github. على Github، ستحصل على شيء مثل [هذا](https://github.com/discourse/discourse/search?q=clickOutsideEventName&unscoped_q=clickOutsideEventName). في معظم الحالات، ستحتوي مصطلح البحث على أكثر من نتيجة واحدة، وسيكون عليك إما أن تكون أكثر تحديدًا أو مسح النتائج يدويًا للعثور على شيء قريب مما تريد.

لذا، الآن انتهى بنا المطاف إلى هذا الملف

[discourse/app/assets/javascripts/discourse/app/mixins/card-contents-base.js at e5dc843185feb268c277bb0ee4db9666d6452783 · discourse/discourse · GitHub](https://github.com/discourse/discourse/blob/e5dc843185feb268c277bb0ee4db9666d6452783/app/assets/javascripts/discourse/app/mixins/card-contents-base.js)

هذا الملف هو [Mixin](https://api.emberjs.com/ember/release/classes/Mixin/methods). لماذا أذكر هذا؟ لأنك بحاجة إلى أن تكون على علم بأن Mixins يمكن مشاركتها في عدد من الأماكن المختلفة. في هذه الحالة، يتم استخدامها لكل من بطاقات المستخدمين وبطاقات المجموعات. لذا، فإن التغييرات التي تجريها هنا ستؤثر على كليهما.

إذا بحثت في الملف، ستجد أن `clickOutsideEventName` يتم تعريفه أولاً هنا

[discourse/app/assets/javascripts/discourse/app/mixins/card-contents-base.js at e5dc843185feb268c277bb0ee4db9666d6452783 · discourse/discourse · GitHub](https://github.com/discourse/discourse/blob/e5dc843185feb268c277bb0ee4db9666d6452783/app/assets/javascripts/discourse/app/mixins/card-contents-base.js#L83)

ثم يتم تمريره هنا كخاصية

[discourse/app/assets/javascripts/discourse/app/mixins/card-contents-base.js at e5dc843185feb268c277bb0ee4db9666d6452783 · discourse/discourse · GitHub](https://github.com/discourse/discourse/blob/e5dc843185feb268c277bb0ee4db9666d6452783/app/assets/javascripts/discourse/app/mixins/card-contents-base.js#L90)

وأخيرًا يتم استهلاكه هنا

[discourse/app/assets/javascripts/discourse/app/mixins/card-contents-base.js at e5dc843185feb268c277bb0ee4db9666d6452783 · discourse/discourse · GitHub](https://github.com/discourse/discourse/blob/e5dc843185feb268c277bb0ee4db9666d6452783/app/assets/javascripts/discourse/app/mixins/card-contents-base.js#L97-L114)

رائع، لكن ماذا يعني كل ذلك؟ حسنًا، إذا نظرت إلى المكان الذي يتم فيه إضافة كل هذا الكود، ستلاحظ أنه داخل `didInsertElement`

[discourse/app/assets/javascripts/discourse/app/mixins/card-contents-base.js at e5dc843185feb268c277bb0ee4db9666d6452783 · discourse/discourse · GitHub](https://github.com/discourse/discourse/blob/e5dc843185feb268c277bb0ee4db9666d6452783/app/assets/javascripts/discourse/app/mixins/card-contents-base.js#L78-L139)

توضح [دليل Ember](https://guides.emberjs.com/v3.4.0/components/the-component-lifecycle/#toc_formatting-component-attributes-with-didreceiveattrs) ما يلي:

> يضمن Ember أنه بحلول الوقت الذي يتم فيه استدعاء `didInsertElement()`:
> 
> 1. تم إنشاء عنصر المكون وإدراجه في DOM.
> 2. يمكن الوصول إلى عنصر المكون عبر خاصية `this.element` الخاصة بالمكون.

لماذا نحتاج إلى هذا؟ لأننا نحتاج إلى معالج mousedown مختلف لبطاقات المستخدمين وبطاقات المجموعات. إذا عدنا قليلاً، ستلاحظ الآن أن معرف العنصر يتم استخدامه في `clickOutsideEventName`

> <https://github.com/discourse/discourse/blob/e5dc843185feb268c277bb0ee4db9666d6452783/app/assets/javascripts/discourse/app/mixins/card-contents-base.js#L81-L83>

والذي، كما ناقشنا أعلاه، يتم تمريره بعد ذلك كخاصية.

الآن، دعنا ننتقل إلى كيف يرتبط كل هذا بما تفعله.

أنت تحاول منع إغلاق البطاقات عندما ينقر المستخدم خارجها. لذا، دعنا نحاول معرفة طريقة للقيام بذلك. إذا كنت تتذكر، ناقشنا كيف يتم استهلاك `clickOutsideEventName` في النهاية هنا

> <https://github.com/discourse/discourse/blob/e5dc843185feb268c277bb0ee4db9666d6452783/app/assets/javascripts/discourse/app/mixins/card-contents-base.js#L97-L114>

باختصار، هذا يضيف معالج mousedown لعنصر HTML عند إدراج بطاقة (في أول عرض للصفحة). ثم نتحقق من هدف حدث mousedown. إذا كان الهدف في مكان ما داخل البطاقة، نتوقف. إذا كان خارج البطاقة، نغلقها عن طريق استدعاء `this._close()`

يتم تعريف `_close()` هنا

[discourse/app/assets/javascripts/discourse/app/mixins/card-contents-base.js at e5dc843185feb268c277bb0ee4db9666d6452783 · discourse/discourse · GitHub](https://github.com/discourse/discourse/blob/e5dc843185feb268c277bb0ee4db9666d6452783/app/assets/javascripts/discourse/app/mixins/card-contents-base.js#L269-L286)

وهذا ما ستحتاج إلى استدعاؤه عند إضافة زر الإغلاق الخاص بك - لكننا سنعود إلى ذلك لاحقًا.

الآن، الهدف هو إزالة معالج mousedown هذا إذا كنت تريد أن لا يؤدي النقر خارج البطاقة إلى إغلاقها. إذن كيف نفعل ذلك؟ حسنًا، سنحتاج إلى تعديل `didInsertElement()` وإليك كيفية القيام بذلك.

تتمتع سمات Discourse بالوصول إلى [واجهة برمجة التطبيقات الإضافية](https://github.com/discourse/discourse/blob/master/app/assets/javascripts/discourse/app/lib/plugin-api.js)، والتي تحتوي على العديد من الطرق التي يمكنك استخدامها. هناك المزيد من التفاصيل حول الأكثر استخدامًا [هنا](https://meta.discourse.org/t/developer-s-guide-to-discourse-themes/93648#heading--4-c)

إذا كنت تتذكر، فإن الملف الذي نعمل عليه هو Mixin. Mixin هو فئة Ember. لذا، فإن الطريقة التي سنستخدمها هي `modifyClass`

[https://github.com/discourse/discourse/blob/master/app/assets/javascripts/discourse/app/lib/plugin-api.js#L121-L124](https://github.com/discourse/discourse/blob/master/app/assets/javascripts/discourse/app/lib/plugin-api.js#L121-L124)

عند استخدام `modifyClass`، يمكنك إما إضافة أو تعديل أو تجاوز طريقة فئة تمامًا. سنركز على تعديل طريقة لأن هذا ما تريد فعله.

نريد تعديل `didInsertElement()` لذا يمكننا فعل شيء مثل هذا

```javascript
api.modifyClass('mixin:card-contents-base', {
  didInsertElement() {
    console.log("foo");
  }
});

```

ونجربها…

حسنًا، لم ينجح ذلك.

 ![تعديل فئة Mixin](https://global.discourse-cdn.com/meta/original/3X/5/6/56665d89853d0ccf6d1a7287e8366448872bfbad.png)

لماذا حدث ذلك؟ حسنًا، اتضح أن طريقة `modifyClass` لا تدعم حاليًا تعديل Mixins (بقدر ما اختبرت) سأقوم بتدوين ملاحظة لمعرفة سبب ذلك والتحقق مما إذا كان بإمكاننا إصلاح ذلك. ولكن في الوقت الحالي، دعنا نعود إلى ما تريد فعله.

حسنًا، لا يمكننا تعديل Mixins، لذا أعتقد أننا عالقون، أليس كذلك؟ لا. دعنا نحفر أعمق قليلاً.

كما ذكرت من قبل، يتم استخدام هذا Mixin بواسطة كل من المستخدم [user-card-contents](https://github.com/discourse/discourse/blob/e5dc843185feb268c277bb0ee4db9666d6452783/app/assets/javascripts/discourse/app/components/user-card-contents.js) و [group-card-contents](https://github.com/discourse/discourse/blob/e5dc843185feb268c277bb0ee4db9666d6452783/app/assets/javascripts/discourse/app/components/group-card-contents.js) مكونات [Ember](https://api.emberjs.com/ember/release/classes/Component) (مرة أخرى، لأن Mixins مصممة لجعل الكود قابلاً لإعادة الاستخدام)

لذا، دعنا ننظر إلى مكون `user-card-contents` هنا

[discourse/app/assets/javascripts/discourse/app/components/user-card-contents.js at e5dc843185feb268c277bb0ee4db9666d6452783 · discourse/discourse · GitHub](https://github.com/discourse/discourse/blob/e5dc843185feb268c277bb0ee4db9666d6452783/app/assets/javascripts/discourse/app/components/user-card-contents.js)

إذا قرأت بعناية، ستلاحظ أننا نستورد أولاً Mixin الذي ناقشناه [هنا](https://github.com/discourse/discourse/blob/e5dc843185feb268c277bb0ee4db9666d6452783/app/assets/javascripts/discourse/app/components/user-card-contents.js#L11)

ثم نقوم بإنشاء مكون Ember جديد ونمرر Mixin إليه.

> <https://github.com/discourse/discourse/blob/e5dc843185feb268c277bb0ee4db9666d6452783/app/assets/javascripts/discourse/app/components/user-card-contents.js#L16>

ماذا يعني ذلك؟ يعني أن `didInsertElement()` لـ `user-card-contents` مُورث فعليًا من Mixin. يمكن قول الشيء نفسه عن `group-card-contents`.

أين يتركنا ذلك؟ حسنًا، هناك أخبار جيدة وأخبار سيئة. الأخبار الجيدة هي أنه إذا كنت تريد إجراء تغييرات على `user-card-contents` دون التأثير على `group-card-contents`، فيمكنك ذلك! الأخبار السيئة هي أنه إذا كنت تريد أن تنطبق تغييراتك على كليهما، فستحتاج إلى تكرار بعض الكود.

دعنا نعود إلى `modifyClass` ونحاول مرة أخرى مع `user-card-contents`. لذا شيء مثل هذا:

```javascript
api.modifyClass('component:user-card-contents', {
  didInsertElement() {
    console.log("foo");
  }
});

```

ونرى ما يحدث…

 ![تعديل محتوى بطاقة المستخدم](https://global.discourse-cdn.com/meta/original/3X/d/9/d94c886acb6c245404cdaa18ae98f7fbcab69df4.png)

voalá 🎉

تم تسجيل التغيير ويمكننا رؤيته في وحدة التحكم، لكننا لم نصل بعد.

لذا، الآن بعد أن أصبح بإمكاننا تعديل `didInsertElement()`، دعنا نحاول العودة إلى ما تحاول فعله. إذا كنت تتذكر، يتم تعريف معالج mousedown في `didInsertElement` هنا

[discourse/app/assets/javascripts/discourse/app/mixins/card-contents-base.js at e5dc843185feb268c277bb0ee4db9666d6452783 · discourse/discourse · GitHub](https://github.com/discourse/discourse/blob/e5dc843185feb268c277bb0ee4db9666d6452783/app/assets/javascripts/discourse/app/mixins/card-contents-base.js#L97-L114)

إذن ماذا يمكننا أن نفعل حيال ذلك؟ حسنًا، الأمر بسيط مثل هذا

`$("html").off(clickOutsideEventName)`

هل سيعمل ذلك؟ لا. إذا قمت بذلك

```javascript
api.modifyClass('component:user-card-contents', {
  didInsertElement() {
    $("html").off(clickOutsideEventName)
  }
});

```

ستنتهي بشيء مكسور. لماذا حدث ذلك؟ لأن هذا ليس تعديلًا للطريقة. هذا تجاوز كامل لطريقة `didInsertElement()` الأساسية لذلك المكون. لذا، لا يتم تطبيق أي من الكود الأساسي فعليًا إذا قمت بذلك.

كيف نصلح هذا؟ حسنًا، اتضح أن Ember لديها شيء يسمى `this._super(...arguments)`

ماذا يفعل ذلك؟ يسمح لك بإضافة أو إضافة كود في إضافة إلى ما تحتويه طريقة الفئة بالفعل. على سبيل المثال، إذا قمت بذلك

```javascript
api.modifyClass('component:user-card-contents', {
  didInsertElement() {
    // الكود الذي تريد إضافته
    $("html").off(clickOutsideEventName);
    // الكود من الأساس
    this._super(...arguments);
  }
});

```

فإن الكود الذي تريد إضافته سيتم تشغيله قبل أي شيء آخر هنا

[discourse/app/assets/javascripts/discourse/app/mixins/card-contents-base.js at e5dc843185feb268c277bb0ee4db9666d6452783 · discourse/discourse · GitHub](https://github.com/discourse/discourse/blob/e5dc843185feb268c277bb0ee4db9666d6452783/app/assets/javascripts/discourse/app/mixins/card-contents-base.js#L79-L138)

ومع ذلك، إذا قمت بذلك…

```javascript
api.modifyClass('component:user-card-contents', {
  didInsertElement() {
    // الكود من الأساس
    this._super(...arguments);
    // الكود الذي تريد إضافته
    $("html").off(clickOutsideEventName);
  }
});

```

فإن كودك سيتم تشغيله بعد أن ينتهي كل شيء هنا

[discourse/app/assets/javascripts/discourse/app/mixins/card-contents-base.js at e5dc843185feb268c277bb0ee4db9666d6452783 · discourse/discourse · GitHub](https://github.com/discourse/discourse/blob/e5dc843185feb268c277bb0ee4db9666d6452783/app/assets/javascripts/discourse/app/mixins/card-contents-base.js#L79-L138)

هذه طريقة رائعة للحفاظ على سمعتك مرنة تجاه التغييرات في الأساس لأن كل شيء في الأساس يتم تشغيله أولاً، ثم يتم تشغيل كودك بعد ذلك. لذا، دعنا نجرب هذا مرة أخرى ونرى ما يحدث.

```javascript
api.modifyClass('component:user-card-contents', {
  didInsertElement() {
    // الكود من الأساس
    this._super(...arguments);
    // الكود الذي تريد إضافته
    $("html").off(clickOutsideEventName);
  }
});

```

و…

 ![خطأ في تعديل الطريقة](https://global.discourse-cdn.com/meta/original/3X/b/8/b8581304cbb66ec083283c33297b64a7e0256802.png)

لماذا يحدث هذا؟ ذلك بسبب سياق كود مختلف. في ملف مكون Ember، يتم تعريف `clickOutsideEventName` بالفعل بحلول الوقت الذي يتم فيه استهلاكه. سمة (Theme) الخاصة بك في ملف مختلف، لذا `clickOutsideEventName` غير معرف هناك.

كيف نصلح ذلك؟ هل تتذكر هذا؟

> <https://github.com/discourse/discourse/blob/e5dc843185feb268c277bb0ee4db9666d6452783/app/assets/javascripts/discourse/app/mixins/card-contents-base.js#L89-L95>

`clickOutsideEventName` هي خاصية للمكون، لذا إذا استخدمت `this.clickOutsideEventName` فيجب أن يعمل. دعنا نجرب ذلك.

```javascript
api.modifyClass('component:user-card-contents', {
  didInsertElement() {
    // الكود من الأساس
    this._super(...arguments);
    // الكود الذي تريد إضافته
    $("html").off(this.clickOutsideEventName);
  },
});

```

وفي الواقع يعمل 🎉

تفتح بطاقات المستخدمين الآن دون أي أخطاء والنقر في أي مكان خارجها لا يفعل شيئًا.

يمكنك فعل نفس الشيء تمامًا لبطاقات المجموعات مثل هذا

```javascript
api.modifyClass('component:group-card-contents', {
  didInsertElement() {
    // الكود من الأساس
    this._super(...arguments);
    // الكود الذي تريد إضافته
    $("html").off(this.clickOutsideEventName);
  },
});

```

الشيء الوحيد المتبقي هو ربط زر الإغلاق هذا بطريقة `_close()` التي ناقشناها سابقًا وهناك ثلاث خطوات لذلك.

1. إضافة إجراء `closeCard` (يمكنك تسميته بما تريد)
2. إضافة زر إلى قالب بطاقة المستخدم
3. استدعاء ذلك الإجراء عند النقر على الزر.

سألتزم ببطاقات المستخدمين للتبسيط. لذا، نضيف هذا (إلى جانب ما ناقشناه بالفعل)

```javascript
api.modifyClass("component:user-card-contents", {
  didInsertElement() {
    this._super(...arguments);
    $("html").off(this.clickOutsideEventName);
  },
  // أشياء جديدة
  actions: {
    closeCard() {
      this._close();
    }
  }
});

```

كل ما يفعله هو استدعاء الطريقة الأساسية `_close()` في كل مرة يتم فيها تشغيل الإجراء المخصص `closeCard`.

بعد ذلك نحتاج إلى إضافة زر إلى قالب بطاقة المستخدم أو شيء مثل هذا

```plaintext
{{d-button
  class="btn-flat"
  action=(action "closeCard")
  icon="times"
}}

```

تبدو نتائجي التقريبية هكذا

وبالطبع يمكنك فعل شيء مماثل لبطاقات المجموعات كما ذكرت أعلاه.

سأترك بطاقة المجموعة والتنفيذ للجوال كتمرين لك لأنك ستستخدم فعليًا نفس المفاهيم التي ناقشناها أعلاه إذا كنت تريد إجراء تغييرات على تلك ولكن يرجى إعلامي إذا واجهت أي مشاكل.

---

_[View the full topic](https://meta.discourse.org/t/sticky-user-card-contents-theme/159875)._
