دليل برمجة إضافات ForumREXAR
إضافة ForumREXAR ملف XML واحد، بدون أي كود JavaScript أو Go. تعلن فيه ماذا تعرض وأين، والمنتدى يفحصه وينفذه بأمان.
هذا الدليل للمطورين ولوكلاء الذكاء الاصطناعي. والنسخة الخام منه للوكلاء: /static/docs/plugin-guide.md
ابدأ في خمس دقائق
- أنشئ ملفاً باسم
hello_box.xmlبترميز UTF-8. - ضع فيه المثال التالي.
- من لوحة التحكم افتح
admin?tab=plugins، ثم ارفع الملف. - تُثبت الإضافة معطلة دائماً، فاضغط زر التفعيل.
- افتح الرئيسية وسترى الصندوق.
<?xml version="1.0" encoding="UTF-8"?>
<plugin schema_version="1.0">
<id>hello_box</id>
<name>صندوق الترحيب</name>
<version>1.0.0</version>
<min_rexar_version>1.0.0</min_rexar_version>
<api_version>1</api_version>
<author>اسمك</author>
<description>يعرض رسالة ترحيب أعلى أقسام الرئيسية.</description>
<icon>👋</icon>
<hook>HOME_ABOVE_FORUMS</hook>
<settings>
<setting key="message" type="string" label="نص الترحيب" default="أهلاً بكم" max_len="100"/>
</settings>
<template><![CDATA[
<div class="vb-bottom-box">
<div class="vb-box-header">ترحيب</div>
<div class="vb-box-body">{{index .settings "message"}}</div>
</div>
]]></template>
</plugin>
عناصر ملف الإضافة
| العنصر | إلزامي | القاعدة |
|---|---|---|
schema_version على plugin | نعم | القيمة 1.0 |
id | نعم | أحرف إنجليزية صغيرة وأرقام و_، من 3 إلى 50 حرفاً |
name | نعم | حتى 100 حرف، بدون < أو > |
version | نعم | مثل 1.0.0، والتحديث يجب أن يكون أحدث |
min_rexar_version | نعم | أقل إصدار تعمل عليه الإضافة، و1.0.0 هو الأدنى |
api_version | نعم | القيمة 1 |
author | نعم | حتى 80 حرفاً |
description | نعم | حتى 300 حرف |
icon | لا | رمز قصير حتى 16 حرفاً |
hook مع template | عند الصندوق | مكان الظهور وقالبه |
data_source | لا | مصدر بيانات أو أكثر مفصولة بفاصلة |
settings | لا | حتى 10 إعدادات |
theme | لا | مظهر يغيّر الألوان |
actions | لا | حتى 10 إجراءات للأعضاء |
page_title مع page_template | عند الصفحة | صفحة خاصة بالإضافة |
يجب أن تحتوي الإضافة على واحد على الأقل من: صندوق، أو مظهر، أو صفحة. والحد الأقصى لحجم الملف 256KB.
المعرفات forum_stats وwho_is_online وlive_chat محجوزة.
ابدأ المعرف باسمك، مثل saleh_top_box، حتى لا يتكرر. وقبل النشر تأكد من عدم استخدامه في قسم الإضافات، فأول من ينشر معرفاً يملكه هناك.
أماكن الظهور
| الاسم | المكان | السياق |
|---|---|---|
HEADER_BELOW | تحت الهيدر في صفحات المنتدى | لا يوجد |
PAGE_BOTTOM | أسفل الصفحة فوق الشريط السفلي | لا يوجد |
SIDEBAR_BOTTOM | أسفل القائمة الجانبية | لا يوجد |
HOME_ABOVE_FORUMS | أعلى أقسام الرئيسية | لا يوجد |
HOME_BELOW_FORUMS | أسفل أقسام الرئيسية | لا يوجد |
FORUM_TOP | أعلى صفحة القسم | قسم |
FORUM_BOTTOM | أسفل صفحة القسم | قسم |
TOPIC_TOP | أعلى الموضوع | موضوع |
TOPIC_BOTTOM | أسفل الموضوع | موضوع |
POST_AUTHOR_BELOW | أسفل بطاقة كاتب كل مشاركة | عضو |
PROFILE_BOTTOM | أسفل الملف الشخصي | عضو |
لا تظهر الإضافات في لوحة التحكم ولا في صفحة التثبيت. ولا يصل إلى النقاش الحي إلا SIDEBAR_BOTTOM. ويُسمح بخمس إضافات مفعلة في المكان الواحد.
القوالب
القالب هو Go html/template داخل <![CDATA[ ... ]]>، والمنتدى يهرّب القيم تلقائياً.
| ما تقرؤه | الصيغة |
|---|---|
| إعداد | {{index .settings "key"}} |
| قائمة بيانات | {{range .data.latest_topics}} ... {{end}} |
| حقل من صف | {{index . "title"}} |
| إعداد من داخل range | {{index $.settings "key"}} |
| إحصائية | {{index .data.forum_stats "members_count"}} |
| سياق الصفحة | {{index .context "username"}} |
| نتيجة تصويت | {{index .storage.poll "yes"}} |
| سجلات الأعضاء | {{range .storage.ideas}} ... {{end}} |
الدوال المسموحة فقط: index وlen وeq وne وlt وle وgt وge وand وor وnot.
القيود:
{{if}}و{{range}}و{{with}}مسموحة، وrangeعلى.dataو.storageفقط، بعمق 2 كحد أقصى.- لا
rangeداخلwith. - لا متغيرات مثل
{{$x := ...}}، ولاdefineأوtemplateأوblock. - لا نصوص ثابتة داخل القوسين مثل
{{"نص"}}؛ النص يُكتب خارجهما، والنصوص داخلها لدوال المقارنة وindexفقط. - حجم ناتج الإضافة حتى 32KB، ووقت عرضها حتى 200ms.
الوسوم المسموحة
div span p strong b em i u br hr ul ol li table thead tbody tr th td a img h3 h4 button textarea input label
الخصائص
| الخاصية | القاعدة |
|---|---|
class | vb-bottom-box وvb-box-header وvb-box-body، أو أسماء تبدأ بـ st-plugin- |
href على a | يبدأ بـ /f.aspx أو https:// |
src على img | يبدأ بـ /static/ فقط |
alt وwidth وheight | على img |
target | _blank فقط |
title وdir وalign | مسموحة |
colspan وrowspan | على td وth |
ممنوع: id وstyle وكل on... وأي data- غير أدوات التفاعل أدناه، وكذلك script وform وiframe وstyle كوسوم.
مصادر البيانات
البيانات عامة بمستوى الزائر: لا أقسام إدارية، ولا مواضيع مخفية، ولا بريد أو IP. وتتحدث كل 30 ثانية تقريباً، والصندوق يُحفظ حتى 60 ثانية. وعدد الصفوف يحدده إعداد باسم limit، وافتراضه 5 وأقصاه 20.
| المصدر | الحقول |
|---|---|
top_posters | rank id username role_color posts_count avatar_url profile_url |
latest_topics | id title url author author_url forum_name forum_url replies_count views_count |
newest_members | id username role_color avatar_url profile_url |
forum_stats | topics_count posts_count members_count online_members online_guests |
forum_stats قيمة واحدة تُقرأ بـ index، والبقية قوائم تُقرأ بـ range.
<?xml version="1.0" encoding="UTF-8"?>
<plugin schema_version="1.0">
<id>guide_latest_box</id>
<name>أحدث المواضيع</name>
<version>1.0.0</version>
<min_rexar_version>1.0.0</min_rexar_version>
<api_version>1</api_version>
<author>اسمك</author>
<description>يعرض أحدث المواضيع مع عدد الأعضاء.</description>
<hook>HOME_BELOW_FORUMS</hook>
<data_source>latest_topics,forum_stats</data_source>
<settings>
<setting key="limit" type="int" label="عدد المواضيع" default="5" min="1" max="20"/>
</settings>
<template><![CDATA[
<div class="vb-bottom-box">
<div class="vb-box-header">أحدث المواضيع</div>
<div class="vb-box-body">
{{range .data.latest_topics}}<a href="{{index . "url"}}">{{index . "title"}}</a>{{end}}
<p>الأعضاء: {{index .data.forum_stats "members_count"}}</p>
</div>
</div>
]]></template>
</plugin>
سياق الصفحة
تقرأ الإضافة بيانات الصفحة الحالية من .context:
| السياق | الحقول |
|---|---|
| عضو | id username role_color role_title avatar_url profile_url posts_count |
| موضوع | id title url author author_url forum_name forum_url replies_count views_count |
| قسم | id name description url topics_count posts_count |
<?xml version="1.0" encoding="UTF-8"?>
<plugin schema_version="1.0">
<id>guide_author_badge</id>
<name>شارة كبار المشاركين</name>
<version>1.0.0</version>
<min_rexar_version>1.0.0</min_rexar_version>
<api_version>1</api_version>
<author>اسمك</author>
<description>شارة تحت الكاتب إذا تجاوز عدداً من المشاركات.</description>
<hook>POST_AUTHOR_BELOW</hook>
<settings>
<setting key="min_posts" type="int" label="الحد الأدنى" default="100" min="1" max="100000"/>
</settings>
<template><![CDATA[
{{if ge (index .context "posts_count") (index .settings "min_posts")}}
<div class="vb-bottom-box"><div class="vb-box-header">عضو مميز</div></div>
{{end}}
]]></template>
</plugin>
الإعدادات
تظهر الإعدادات للمدير في لوحة التحكم، وتُفحص قيمها عند الحفظ.
| النوع | الخصائص |
|---|---|
string | max_len حتى 250، وبدون < أو > في القيمة |
int | min وmax إلزاميان |
bool | default يكون true أو false |
color | لون بصيغة #1a2b3c، ويظهر كمنتقي ألوان |
select | عناصر <option value="..." label="..."/> داخل الإعداد |
كل إعداد يحتاج key وtype وlabel وdefault. والمفتاح أحرف صغيرة وأرقام و_، من 2 إلى 30 حرفاً.
المظاهر
عنصر <theme> يحمل CSS يغيّر الألوان والخطوط، ويمكن استخدام إعدادات اللون فيه بصيغة var(--setting-key).
الخصائص المسموحة: color وbackground وbackground-color وbackground-image وborder وأنواعه وborder-radius وoutline-color وbox-shadow وtext-shadow وtext-decoration-color وfont-family وfont-weight وfont-style وcaret-color وaccent-color، إضافة إلى متغيرات CSS مثل --startimes-blue.
الدوال المسموحة: rgb وrgba وhsl وhsla وlinear-gradient وradial-gradient وvar.
الممنوع: url() و@import وأي قاعدة @، وposition وdisplay وopacity وwidth وخصائص التخطيط، و::before و::after ومحددات الخصائص [...].
المحولات المسموحة: :hover و:focus و:active و:visited و:root و:first-child و:last-child.
يعمل مظهر واحد فقط في كل مرة، ولا يُطبق على لوحة التحكم. وللمدير زر معاينة قبل التفعيل.
<?xml version="1.0" encoding="UTF-8"?>
<plugin schema_version="1.0">
<id>guide_green_theme</id>
<name>المظهر الأخضر</name>
<version>1.0.0</version>
<min_rexar_version>1.0.0</min_rexar_version>
<api_version>1</api_version>
<author>اسمك</author>
<description>يغيّر ترويسات المنتدى إلى الأخضر.</description>
<settings>
<setting key="primary" type="color" label="اللون الأساسي" default="#047857"/>
</settings>
<theme><![CDATA[
:root { --startimes-blue: var(--setting-primary); }
.table-columns-header, .table-columns-header th, .vb-box-header {
background: var(--setting-primary) !important;
}
]]></theme>
</plugin>
التفاعل
المطور يعلن الإجراءات، والمنتدى ينفذها. وكل إجراء يتطلب عضواً مسجلاً.
| الخاصية | vote تصويت | entry نص |
|---|---|---|
id | إلزامي | إلزامي |
options | إلزامي، حتى 20 خياراً | غير مسموح |
max_len | غير مسموح | افتراضي 200، وأقصى 500 |
max_entries | غير مسموح | افتراضي 100، وأقصى 500 |
cooldown | ثوانٍ، افتراضي 30، وأقل قيمة 3 | كذلك |
الخيار total محجوز لمجموع الأصوات. وعند تجاوز max_entries يُحذف أقدم سجل. والبيانات في ملف مستقل حتى 2MB، وتبقى عند تحديث الإضافة، وتُحذف بحذفها. وللمدير زر مسح البيانات.
أدوات الواجهة
| الخاصية | الوسم | الوظيفة |
|---|---|---|
data-plugin-action | button | اسم الإجراء |
data-plugin-value | button | خيار التصويت |
data-plugin-field | button | اسم الحقل المرتبط بالزر |
data-plugin-input | input وtextarea | اسم الحقل |
data-plugin-status | div وspan وp | مكان رسالة النجاح أو الخطأ |
data-plugin-open | button | يفتح نافذة |
data-plugin-close | button | يغلق النافذة |
data-plugin-modal | div | جسم النافذة، وعنصره الأول هو محتواها |
قيم هذه الخصائص أحرف إنجليزية وأرقام و_ و- حتى 40 حرفاً. وinput نوعه text فقط، وbutton لا يرسل نموذجاً. وخصائص الحقول المسموحة placeholder وmaxlength وrows.
الصفحة الخاصة
رابطها /f.aspx?plugin=ID. وتعرف الصفحة الزائر عبر .viewer.logged_in و.viewer.username، وصوته عبر {{index .viewer.votes "poll"}}. أما الصناديق فمشتركة بين الزوار، فلا تعرف الزائر الحالي.
<?xml version="1.0" encoding="UTF-8"?>
<plugin schema_version="1.0">
<id>guide_poll_page</id>
<name>استفتاء واقتراحات</name>
<version>1.0.0</version>
<min_rexar_version>1.0.0</min_rexar_version>
<api_version>1</api_version>
<author>اسمك</author>
<description>استفتاء في الرئيسية وصفحة لاقتراحات الأعضاء.</description>
<hook>HOME_ABOVE_FORUMS</hook>
<actions>
<action id="poll" type="vote" options="yes,no" cooldown="5"/>
<action id="ideas" type="entry" max_len="300" max_entries="200" cooldown="30"/>
</actions>
<template><![CDATA[
<div class="vb-bottom-box">
<div class="vb-box-header">هل يعجبك المنتدى؟</div>
<div class="vb-box-body">
<button data-plugin-action="poll" data-plugin-value="yes">نعم ({{index .storage.poll "yes"}})</button>
<button data-plugin-action="poll" data-plugin-value="no">لا ({{index .storage.poll "no"}})</button>
<button data-plugin-open="about">التفاصيل</button>
<a href="/f.aspx?plugin=guide_poll_page">الاقتراحات</a>
<span data-plugin-status="box"></span>
<div data-plugin-modal="about">
<div>
<p>صوتك يُحتسب مرة واحدة ويمكنك تغييره.</p>
<button data-plugin-close="about">إغلاق</button>
</div>
</div>
</div>
</div>
]]></template>
<page_title>اقتراحات الأعضاء</page_title>
<page_template><![CDATA[
<div class="vb-bottom-box">
<div class="vb-box-header">اقتراحات الأعضاء</div>
<div class="vb-box-body">
{{if .viewer.logged_in}}
<textarea data-plugin-input="ideas" maxlength="300" rows="3" placeholder="اكتب اقتراحك"></textarea>
<button data-plugin-action="ideas" data-plugin-field="ideas">إرسال</button>
<span data-plugin-status="page"></span>
{{end}}
{{range .storage.ideas}}
<p><a href="{{index . "profile_url"}}">{{index . "username"}}</a>: {{index . "text"}}</p>
{{end}}
</div>
</div>
]]></page_template>
</plugin>
حقول سجلات .storage: id وusername وprofile_url وtext وtime، وتُعرض آخر 50 سجلاً.
التحديث
ارفع ملفاً بنفس id ورقم version أعلى، مع تحديد خيار "تحديث إضافة مثبتة". تعود الإضافة معطلة للمراجعة، وتبقى إعداداتها وبياناتها.
عند فشل العرض 5 مرات متتالية تتعطل الإضافة تلقائياً، ويظهر السبب في لوحة التحكم. وخيار REXAR_SAFE_MODE=1 في بيئة التشغيل يوقف كل الإضافات.
رسائل الرفض الشائعة
| الرسالة | السبب والحل |
|---|---|
forbidden HTML tag | وسم غير مسموح، راجع قائمة الوسوم |
disallowed CSS class | استخدم st-plugin- قبل اسم الكلاس |
attribute "style" is forbidden | لا style داخل القالب، استخدم <theme> |
forbidden template function | دالة غير مسموحة، راجع قائمة الدوال |
direct string literal | انقل النص خارج {{ }} |
custom template variables | احذف المتغيرات واستخدم index |
a href must start with | الرابط يبدأ بـ /f.aspx أو https:// |
img src must start with /static/ | الصور من ملفات الموقع فقط |
unsupported or unknown <hook> | اسم مكان غير صحيح، راجع الجدول |
property ... is not allowed in <theme> | خاصية CSS غير مسموحة |
requires ForumREXAR version | المنتدى أقدم من min_rexar_version |
يجب أن يكون أحدث | ارفع رقم version قبل التحديث |
تعليمات لوكلاء الذكاء الاصطناعي
عند إنشاء إضافة التزم بما يلي:
- أخرج ملف XML واحداً كاملاً بترميز UTF-8، ولا تكتب JavaScript أو CSS خارج
<theme>. - استخدم فقط العناصر والأسماء الواردة هنا، ولا تخمن أسماء بيانات أو أماكن غير مذكورة.
- ضع القوالب والمظاهر داخل
<![CDATA[ ... ]]>. - اجعل
idفريداً بأحرف صغيرة، وابدأ الإصدار من1.0.0. - للتنسيق استخدم
vb-bottom-boxوvb-box-headerوvb-box-bodyلتطابق شكل المنتدى. - إذا طلب المستخدم شيئاً غير مدعوم، فأخبره بالقيد بدل محاولة الالتفاف عليه.
- بعد الرفع اقرأ رسالة الرفض، وأصلح السبب نفسه فقط، ثم أعد المحاولة.