JavaScript
- محمد علایی
- منتشر شده در
- زمان خواندن 10 دقیقه
افزودن جاوااسکریپت به افزونه شما
در این بخش، آنچه برای افزودن جاوااسکریپت به افزونه جوملای خود باید انجام دهید را بررسی میکنیم.
فایلهای کد جاوااسکریپت
برای افزودن فایلهای جاوااسکریپت به افزونه خود، باید از مدیریت دارایی وب جوملا (Joomla Web Asset Manager) استفاده کرده و مراحل زیر را دنبال کنید.
1- ذخیره فایلهای جاوااسکریپت در پوشه media
شما باید فایلهای JS خود را در پوشه media/js در محیط توسعهتان ذخیره کنید، برای مثال:
media
├─ css
└─ js
├─ myjs1.js
└─ myjs2.js
این فایلها سپس باید به پوشه media در نمونه جوملای شما کپی شوند، بنابراین در فایل مانیفست نصب افزونه باید اینگونه تعریف شود:
فایل مانیفست افزونه
<media destination="com_example" folder="media">
<folder>js</folder>
</media>
در اینجا (و در سایر بخشهای این صفحه مستندات)، باید "com_example" را با نوع و نام افزونه خود جایگزین کنید.
وقتی افزونه خود را نصب میکنید، جوملا فایلهای js شما را به پوشه media/com_example/js کپی خواهد کرد.
نکته
شما همچنین میتوانید یک کتابخانه جاوااسکریپت برای افزونه خود پیادهسازی کنید، برای مثال در پوشه توسعه media/mylib/js/ حاوی فایلهای سورس js. این کتابخانه هنگام نصب افزونه به مسیر media/com_example/mylib/js نگاشت داده خواهد شد.
2- ایجاد فایل media/joomla.asset.json
یک فایل joomla.asset.json در پوشه media خود ایجاد کنید، همانطور که در بخش مدیریت دارایی وب - تعریف آمده است، برای مثال:
{
"$schema": "https://developer.joomla.org/schemas/json-schema/web_assets.json",
"name": "com_example",
"version": "1.0.0",
"description": "Example joomla.asset.json file",
"license": "GPL-2.0+",
"assets": [
{
"name": "com_example.myjs1",
"type": "script",
"uri": "com_example/myjs1.js",
"attributes": {
"defer": true
},
"dependencies": [
"core", "jquery"
],
"version": "1.2.0"
},
{
"name": "com_example.myjs2",
"type": "script",
"uri": "com_example/myjs1.min.js",
"attributes": {
"async": true
},
"dependencies": [
"com_example.myjs1", "form.validate"
],
"version": "1.0.3"
}
]
}
در آرایهی assets کلیدهای زیر وجود دارند:
- name– شما میتوانید هر رشتهای به این کلید اختصاص دهید، اما معمولاً نام افزونه خود را به همراه یک نقطه و نام فایل JavaScript میگذارند. این نام در کد PHP شما برای وارد کردن فایل JavaScript به صفحه وب استفاده میشود. گذاشتن نام افزونه باعث میشود که این نام با داراییهای هسته جوملا یا افزونههای دیگر تداخل نداشته باشد.
- type– نوع دارایی است و برای جاوااسکریپت مقدار آن "script" است.
- uri– این مسیر به جوملا میگوید که کد شما کجا قرار دارد. مسیر زیر شاخهی پوشه media است ولی قسمت js در مسیر حذف شده است. شما میتوانید از نسخه مینیمایز شده جاوااسکریپت هم استفاده کنید (مانند مثال myjs2). اگر هر دو فایل myjs2.js و myjs2.min.js در پوشه js موجود باشد، وقتی حالت Debug در تنظیمات کلی فعال شود، Web Asset Manager نسخه غیرمینیمایز شده را بارگذاری میکند.
- attributes– این صفات به تگ `<script>` در خروجی HTML صفحه اضافه میشوند.
- dependencies– نام یا نامهای داراییهای دیگری که کد شما به آنها وابسته است، مثلاً در json بالا:
- "com_example.myjs1" وابسته به "core" جوملا (که در media/system/joomla.asset.json به کتابخانه core.js اشاره دارد) و همچنین "jquery" (در media/vendor/joomla.asset.json تعریف شده) است.
- "com_example.myjs2" وابسته به "form.validate" (در media/system/joomla.asset.json، مربوط به اعتبارسنجی فرمها) است.
- "com_example.myjs2" همچنین وابسته به "com_example.myjs1" است (در همان فایل joomla.asset.json)، بنابراین وقتی myjs2.js بارگذاری شود، jomla نیز myjs1.js و همه وابستگیهای آن را بارگذاری میکند.
Web Asset Manager ترتیب تگهای `<script>` را طوری تنظیم میکند که مرورگر ابتدا وابستگیها را پردازش کند.
چگونه نام کتابخانههای جوملا برای وابستگیها را بدانیم؟
ممکن است جستجو در مستندات کتابخانههای JavaScript جوملا مفید باشد، ولی گاهی باید خود کدها را بررسی کنید:
- داراییهای کتابخانه جوملا در media/system/joomla.asset.json هستند و به کد در media/system/js اشاره دارند.
- داراییهای کتابخانه vendor در media/vendor/joomla.asset.json هستند و به کد در media/vendor/js اشاره دارند.
این دو فایل joomla.asset.json همیشه توسط جوملا پردازش میشوند و داراییهای آنها همیشه در دسترس خواهند بود.
- version– نسخهای است که میخواهید به کد JS خود اختصاص دهید. وقتی کد را بهروزرسانی میکنید و شماره نسخه را افزایش میدهید، جوملا باعث میشود که مرورگر کد جدید را بارگذاری کند و نسخه کش شده را استفاده نکند. (جوملا این کار را با افزودن شماره نسخه بهصورت پارامتر در URL فایل js انجام میدهد).
کپی فایل joomla.asset.json به فولدر media توسط جوملا:
در فایل manifest افزونه باید این بخش را داشته باشید:
<media destination="com_example" folder="media">
<filename>joomla.asset.json</filename>
<folder>js</folder>
</media>
نکته:
اگر افزونه شما فقط ۱ یا ۲ دارایی دارد، ممکن است ثبت مستقیم آن در Web Asset Manager سادهتر باشد، بدون نیاز به فایل joomla.asset.json. مثلاً با استفاده از متدهای زیر:
$wa = Factory::getApplication()->getDocument()->getWebAssetManager();
$wa->registerScript('com_example.myjs1', 'com_example/myjs1.js', [], ['defer' => 'true'], ["core", "jquery"]);
یا برای ثبت و استفاده همزمان:
$wa = Factory::getApplication()->getDocument()->getWebAssetManager();
$wa->registerAndUseScript('com_example.myjs1', 'com_example/myjs1.js', [], ['defer' => 'true'], ["core", "jquery"]);
اسکریپتهای درونخطی (Inline Scripts)
گاهی لازم است کدهای جاوااسکریپت خود را به صورت پویا تولید کنید، نه اینکه آنها را در یک فایل ذخیره کنید.
در این حالت، میتوانید از تابع `addInlineScript` مدیر دارایی وب (Web Asset Manager) استفاده کنید، برای مثال:
$hi = "function sayhi() { alert('Hi!'); }";
$wa = Factory::getApplication()->getDocument()->getWebAssetManager();
$wa->addInlineScript($hi);
ارسال متغیرها به جاوااسکریپت
شما میتوانید متغیرها را از کد PHP خود به کد جاوااسکریپت با استفاده از متد `addScriptOptions` کلاس Document ارسال کنید.
برای مثال:
$phpvars = array('alpha' => 1, 'beta' => 'test', 'gamma' => null);
$document = Factory::getApplication()->getDocument();
$document->addScriptOptions('com_example.myvars', $phpvars);
سپس میتوانید این متغیرها را در جاوااسکریپت بازیابی کنید:
var jsvars = Joomla.getOptions('com_example.myvars');
console.log(jsvars);
این در کنسول مرورگر ساختار شیء جاوااسکریپت زیر را نمایش میدهد:
{alpha: 1, beta: "test", gamma: null}
میتوانید این کار را چندین بار با کلیدهای مختلف انجام دهید (در مثال بالا، کلید `'com_example.myvars'` است).
بهتر است نام افزونه (extension) خود را در کلید وارد کنید چون دادهها در فضای ذخیرهسازی گزینههای سراسری (global "options storage") عبور میکنند و ممکن است با دادههای افزونههای دیگر تداخل پیدا کنند.
تابع `Joomla.getOptions` در فایل کتابخانهی `core.js` هستهی جوملا قرار دارد، پس دارایی جاوااسکریپت شما باید کتابخانهی `"core"` را به عنوان وابستگی داشته باشد.
ارسال ثابتهای زبان به جاوااسکریپت
میتوانید ثابتهای متنی زبان را به جاوااسکریپت از طریق تابع `Text::script` ارسال کنید:
use Joomla\CMS\Language\Text;
Text::script('COM_EXAMPLE_ERROR_MESSAGE');
باید مطمئن شوید که زبان مربوط به افزونه شما بارگذاری شده است – جوملا این کار را به صورت خودکار برای کامپوننتها (از طریق کدهای کتابخانه MVC) انجام میدهد ولی برای ماژولها یا پلاگینها به صورت خودکار صورت نمیگیرد.
در داخل جاوااسکریپت میتوانید رشته ترجمهشده را به این شکل استفاده کنید:
const errorMessage = Joomla.Text._('COM_EXAMPLE_ERROR_MESSAGE');
و میتوانید پیام خطا را در بخش پیامهای صفحه جوملا نمایش دهید:
Joomla.renderMessages({ 'error': [errorMessage] });
اگر ثابتهای زبانی شما شامل `%s` برای پارامترها باشند، باید در جاوااسکریپت از توابعی برای جایگزینی این `%s` ها استفاده کنید.
تابع جاوااسکریپت `Joomla.Text._` در فایل `core.js` قرار دارد، ولی تابع `Text::script` در PHP تضمین میکند که این کتابخانه بارگذاری شده باشد.
تابع جاوااسکریپت `Joomla.renderMessages` در فایل `messages.js` است، بنابراین دارایی شما باید `"messages"` را به عنوان وابستگی شامل شود.
مثالها
آموزش توسعه ماژول - مرحله 7: افزودن جاوااسکریپت شامل مثالهایی از:
- افزودن فایلهای جاوااسکریپت
- ارسال متغیرها به جاوااسکریپت
آموزش توسعه ماژول - مرحله 9: افزودن Ajax شامل مثالهایی از:
- ارسال ثابتهای زبان به جاوااسکریپت
- نمایش پیامها در داخل جاوااسکریپت
Ajax و JsonResponse
این بخش توضیح میدهد که چگونه در کامپوننتهای جوملا از Ajax استفاده کنید، از جمله نحوه استفاده از کلاس `JsonResponse` برای ارسال پاسخ به سمت جاوااسکریپت از سرور.
در پایان این بخش، لینک نمونهای از کامپوننت موجود است که میتوانید آن را دانلود و به عنوان مثال اجرا کنید.
شما همچنین میتوانید از Ajax در ماژولها، پلاگینها و قالبهای جوملا نیز استفاده کنید که در سند بعدی به آن پرداخته شده است.
فرض بر این است که شما با استفاده کلی Ajax آشنا هستید.
مسیریابی (Routing)
وقتی از جاوااسکریپت یک درخواست Ajax به آدرس جوملا ارسال میکنید، جوملا به همان شیوه یک درخواست HTTP عادی آن را مسیر یابی میکند؛ پردازش ویژهای برای درخواستهای Ajax ندارد. جوملا کامپوننت مربوط به آن URL را پیدا کرده و کنترل را به آن میدهد.
برای استفاده از Ajax در داخل یک کامپوننت، باید URLای که به کامپوننت شما مسیر میدهد را مشخص کنید.
اگر از Ajax در ماژول، پلاگین یا قالب استفاده میکنید، باید درخواست را به کامپوننت `com_ajax` جوملا ارسال کنید که به عنوان نماینده (Proxy) برای ماژول/پلاگین/قالب شما عمل میکند. این موضوع در سند بعدی توضیح داده شده است.
در داخل کامپوننت خود باید از رویکرد MVC استفاده کرده و قابلیتها را میان کنترلرها، مدلها و ویوها تفکیک کنید.
کد پیشفرض جوملا برای Extension/Dispatcher پارامتر URL به نام `task` را برای مشخص کردن کلاس کنترلر و متد مربوطه استفاده میکند.
مثلاً اگر پارامتر task را روی `"ajax.divide"` تنظیم کنید، کد پیشفرض Dispatcher کنترلر `AjaxController` شما را ساخته و متد `divide` آن را فراخوانی میکند.
JsonResponse – استفاده پایه
وقتی منطق برنامه برای دریافت دادههای لازم انجام شد، میخواهید آن دادهها را به کد جاوااسکریپت در پاسخ Ajax بفرستید. اینجا کلاس `JsonResponse` به کمک شما میآید.
مثال کاربردی ساده:
use Joomla\CMS\Response\JsonResponse;
use Joomla\CMS\MVC\Controller\BaseController;
class AjaxController extends BaseController
{
public function divide()
{
try
{
// اگر از کلاسهای MVC جوملا استفاده میکنید، نمونه Application در سازنده BaseController تزریق شده و در متغیر $app ذخیره میشود
$anyParam = $this->app->input->get('anyparam');
$result = $this->getModel('example')->calculateSomething($anyParam);
echo new JsonResponse($result);
}
catch(\Exception $e)
{
echo new JsonResponse($e);
}
}
}
در حالت پیشفرض، خروجی چیزی است که مدل محاسبه میکند و به یک شیء `JsonResponse` داده میشود و مستقیماً چاپ میشود. این به صورت خودکار یک رشته JSON مشابه این را ایجاد میکند:
{"success":true,"message":null,"messages":null,"data":{"result1":1,"result2":42, ...}}
در فیلد `data` میتوانید هر آرایه، شی یا مقدار دلخواه خود را ارسال کنید و فِلَگ `success` به طور خودکار روی true تنظیم میشود.
اگر در مدل یک استثنا (Exception) رخ دهد، آن استثنا به طور مستقیم به یک شیء جدید `JsonResponse` داده میشود که خروجی مانند این تولید میکند:
{"success":false,"message":"This is the message of the exception","messages":null,"data":null}
چون این یک استثنا است، فلَگ `success` به صورت خودکار false میشود و پیام استثنا (Exception) پیام اصلی پاسخ خواهد بود.
JsonResponse – اضافه کردن پیام
اگر میخواهید به پاسخ `JsonResponse` خود پیام اضافه کنید، میتوانید این کار را انجام دهید، البته به شرطی که اول پارامتر Exception به سازنده ارسال نکرده باشید.
echo new JsonResponse($result, Text::_('COM_EXAMPLE_AJAX_SUCCESS'));
که پاسخی مشابه این ارسال میکند:
{"success":true,"message":"Success message!","messages":null,"data":{"result1":1,"result2":42, ...}}
همچنین میتوانید فلَگ خطا (error) را با پارامتر سوم سازنده روی true بگذارید:
echo new JsonResponse($result, Text::_('COM_EXAMPLE_AJAX_FAILURE'), true);
که چنین پاسخی به جاوااسکریپت ارسال میکند:
{"success":false,"message":"Failure message!","messages":null,"data":{"result1":1,"result2":42, ...}}
به این ترتیب حتی در صورت خطا میتوانید دادههایی را نیز ارسال کنید.
نمایش پیام در قالب (Template)
برای نمایش پیام در ناحیه پیامهای صفحه جوملا، میتوانید از تابع جاوااسکریپتی `Joomla.renderMessages` استفاده کنید، اما باید پیام را به این شکل ارسال کنید:
Joomla.renderMessages({"notice": [result.message]});
زیرا تابع `Joomla.renderMessages` انتظار دارد یک شیء JSON داشته باشد که:
- کلید آن نوع پیام باشد (مثلاً "notice"، "error"، "warning" و غیره)
- مقدار، آرایهای از رشتهها باشد
این تابع در فایل `media/system/js/messages.js` قرار دارد، بنابراین باید `"messages"` را به عنوان وابستگی در فایل `joomla.asset.json` افزونه خود اضافه کنید.
JsonResponse – پیامهای صفبندی شده (Enqueued messages)
به طور پیشفرض، وقتی از `JsonResponse` استفاده میکنید، همه پیامهای صفبندی شده (Enqueued Messages) را گرفته و به عنوان پارامتر `"messages"` در پاسخ JSON ارسال میکند.
ساختار این پارامتر `"messages"` به گونهای است که به طور مستقیم میتوانید در جاوااسکریپت این را به `Joomla.renderMessages` بدهید، مثلاً:
Joomla.renderMessages(result.messages);
تا این پیامها در ناحیه پیامها نمایش داده شوند.
اما اگر خودتان هم با `Joomla.renderMessages` یک پیام موفقیت یا خطا ارسال کنید، فراخوانی دوم `Joomla.renderMessages` به صورت پیشفرض پیامهای قبلی را پاک میکند و پیام جدید جایگزین آنها میشود.
برای جلوگیری از این اتفاق، در فراخوانی دوم باید بار سوم (پارامتر سوم) `true` بگذارید:
Joomla.renderMessages(result.messages, undefined, true);
اگر نمیخواهید `JsonResponse` پیامهای صفبندی شده را در خروجی ارسال کند، در فراخوانی PHP سازنده `JsonResponse` پارامتر چهارم `$ignoreMessages` را برابر `true` قرار دهید:
echo new JsonResponse($result, Text::_('COM_EXAMPLE_AJAX_SUCCESS'), null, true);
نمونه کامپوننت
کامپوننت `com_ajaxdemo` بسیاری از امکانات گفته شده در این بخش را نشان میدهد.
میتوانید `com_ajaxdemo` را از اینجا دانلود کنید.
استفاده از com_ajax برای ماژولها، پلاگینها و قالبها
این بخش نشان میدهد چگونه میتوانید در ماژولها، پلاگینها و قالبهای جوملا از Ajax استفاده کنید با کمک کامپوننت `com_ajax`.
از آنجا که نمیتوانید به صورت مستقیم یک درخواست HTTP به ماژول/پلاگین/قالب ارسال کنید، باید از `com_ajax` به عنوان پراکسی (واسط) استفاده کنید که بر اساس پارامترهای درخواست Ajax کنترل را به افزونه شما منتقل میکند.
نکته:
همچنین میتوانید از `com_ajax` به روشی غیرمرتبط با Ajax برای تعریف URL جهت انجام کارهای خاص (ad hoc) استفاده کنید.
ماژولها
برای ارسال درخواست Ajax به یک ماژول، باید پارامترهای زیر را در URL درخواست Ajax قرار دهید:
- `option` - مقدار آن باید `com_ajax` باشد.
- `module` - نام ماژول بدون پیشوند `mod_`.
- `method` - نام متدی از کلاس هِلپر (Helper) ماژول که در انتهای آن "Ajax" اضافه شده است (برای مثال `countAjax`).
- `format` - فرمت پاسخ، که میتواند `"json"` یا `"raw"` باشد.
متد مورد نظر باید یک تابع عمومی (public instance function) در کلاس Helper ماژول باشد. نام کلاس Helper باید به شکل `<Modulename>Helper` باشد و به صورت استاندارد در namespace های جوملا قرار گیرد.
متد Helper فقط باید دادههای مورد نیاز را برگرداند؛ `com_ajax` بر اساس پارامتر `format` پاسخ را به صورت JSON یا raw نمایش میدهد.
اگر `format=raw` انتخاب شود، خروجی دقیقا همان چیزی خواهد بود که از متد Helper برمیگردد و مستقیماً چاپ میشود.
مثال ماژول
در آموزش ماژول مرحله ۹ (Ajax) نمونه کاملی وجود دارد:
- نام ماژول: `mod_hello`
- متد هِلپر: `countAjax()`
- فرمت پاسخ: `json`
بنابراین، URL به این شکل خواهد بود:
index.php?option=com_ajax&module=hello&method=count&format=json
پلاگینها
در این حالت، `com_ajax` یک رویداد (Event) به نام `OnAjax<Methodname>` ایجاد میکند که پلاگین شما باید به آن گوش دهد.
برای ارسال درخواست Ajax به پلاگین باید پارامترهای زیر را در URL قرار دهید:
- `option` - مقدار `com_ajax`
- `plugin` - نام رویداد با پیشوند `OnAjax` حذف شده (مثلاً `divide` برای رویداد `OnAjaxDivide`)
- `format` - فرمت پاسخ که یا `json` یا `raw` است.
پلاگین باید در گروه "ajax" باشد، پس در فایل مانیفست آن باید داشته باشید:
<extension method="upgrade" type="plugin" group="ajax">
پلاگین باید نتیجه را به آرگومان `result` رویداد اضافه کند. `com_ajax` پاسخ را با کلاس `JsonResponse` به صورت JSON یا raw ارسال خواهد کرد.
اگر پلاگین استثنایی (Exception) پرتاب کند، توسط `com_ajax` به عنوان شکست ثبت میشود و متن استثنا به عنوان پیام خطا در پاسخ Ajax فرستاده میشود.
مثال پلاگین
به سادگی میتوانید کامپوننت نمونه `com_ajaxdemo` را به این شکل تغییر دهید:
در فایل `media/js/divide.js` خط:
let url = vars.root + 'index.php?option=com_ajaxdemo&format=json&task=ajax.divide';
را به
let url = vars.root + 'index.php?option=com_ajax&plugin=divide&format=json';
تغییر دهید.
این باعث میشود درخواست Ajax به `com_ajax` ارسال شود که پلاگینهای گروه `ajax` را بارگذاری کرده و رویداد `OnAjaxDivide` را اجرا میکند.
میتوانید پلاگین `plg_ajaxdemo` را دانلود، نصب و فعال کنید. این پلاگین عملیات تقسیم a/b را مشابه کامپوننت `com_ajaxdemo` انجام میدهد.
قالبها (Templates)
برای ارسال درخواست Ajax به یک قالب، باید پارامترهای زیر را در URL درخواست HTTP Ajax قرار دهید:
- `option` - مقدار باید `com_ajax` باشد.
- `template` - نام قالب مورد نظر (مثلاً `cassiopeia`).
- `method` - نام متدی که باید فراخوانی شود؛ وقتی `Ajax` به انتهای نام متد اضافه میشود، این نام مربوط به متد در کلاس Helper قالب است که باید فراخوانی شود.
- `format` - فرمت پاسخ که میتواند `"json"` یا `"raw"` باشد.
نکات مهم درباره متد فراخوانی شده
- متدی که فراخوانی میکنید باید یک تابع **public static** در کلاس Helper قالب باشد.
- کلاس Helper قالب باید به صورت `Tpl<TemplateName>Helper` نامگذاری شود، یعنی برای قالب `cassiopeia` باید نام کلاس `TplCassiopeiaHelper` باشد.
- این کلاس در فایل `helper.php` در دایرکتوری قالب قرار میگیرد.
متد Helper فقط باید دادههای مورد نیاز را برگرداند؛ سپس کامپوننت `com_ajax` با توجه به پارامتر `format` پاسخ را به صورت JSON یا خروجی خام (raw) ارسال میکند.
اگر `format=raw` انتخاب شود، هر چیزی که متد Helper برگرداند مستقیماً به خروجی (echo) ارسال میشود.
مثال قالب
برای مثال، میتوانید کد کامپوننت نمونه `com_ajaxdemo` را در بخش مستندات Ajax مانند زیر تغییر دهید:
در فایل `media/js/divide.js` خط زیر:
let url = vars.root + 'index.php?option=com_ajaxdemo&format=json&task=ajax.divide';
را به این صورت تغییر دهید:
let url = vars.root + 'index.php?option=com_ajax&template=cassiopeia&format=json';
فایل helper.php قالب cassiopeia
سپس فایل زیر را در مسیر `templates/cassiopeia/helper.php` ذخیره کنید:
<?php
defined('_JEXEC') or die;
use Joomla\CMS\Factory;
class TplCassiopeiaHelper
{
public static function divideAjax()
{
$app = Factory::getApplication();
$input = $app->input;
$a = $input->get("a", 0, "float");
$b = $input->get("b", 0, "float");
$result = self::_divide($a, $b);
return $result;
}
private static function _divide($a, $b)
{
if ($b == 0)
{
throw new \Exception('Division by zero!');
}
return $a/$b;
}
}
نکته مهم
هرگز نباید فایلها را در دایرکتوریهای هستهی جوملا (Core) ذخیره کنید.
اما اگر قالب خودتان را ساختهاید یا قالب فرزند (Child Template) از `cassiopeia` ساختهاید، میتوانید این فایل `helper.php` را داخل دایرکتوری آن قالب قرار دهید و استفاده کنید.
کتابخانه جاوا اسکریپت جوملا
این بخش جزئیات توابع جاوا اسکریپت سمت کلاینت که با جوملا ارائه میشوند را ارائه میدهد.
فایل core.js در جوملا
فایل `core.js` یک آبجکت سراسری با نام `Joomla` ایجاد میکند و امکانات پایهای سمت کلاینت را فراهم میآورد، مانند ذخیرهسازی گزینهها (Options)، ترجمهها، درخواستهای Ajax و غیره.
برای فعالکردن این فایل در صفحه، باید از WebAssetManager استفاده کنید:
$wa->useScript('core');
گزینههای سمت کلاینت (Client side options)
جوملا یک روش عمومی برای به اشتراک گذاشتن تنظیمات اسکریپت بین سرور و کلاینت دارد.
برای ارسال گزینههای مورد نظر از PHP به جاوااسکریپت، مثلاً:
$doc = Joomla\CMS\Factory::getApplication()->getDocument();
$doc->addScriptOptions('my_extension_options', ['foo' => 'bar']);
و در سمت کلاینت (جاوااسکریپت) میتوانید این گزینهها را بخوانید:
console.log(Joomla.getOptions('my_extension_options'));
ترجمههای سمت کلاینت (Client side translations)
برای افزودن رشتههای ترجمه به اسکریپت، در اسکریپت یا لایه خود، این رشتهها را اضافه کنید:
Joomla\CMS\Language\Text::script('LANG_CONSTANT1');
Joomla\CMS\Language\Text::script('LANG_CONSTANT2');
Joomla\CMS\Language\Text::script('LANG_CONSTANT3');
سپس در کد جاوااسکریپت میتوانید به این صورت از آنها استفاده کنید:
console.log(Joomla.Text('LANG_CONSTANT1', 'Default string1'));
console.log(Joomla.Text('LANG_CONSTANT2', 'Default string2'));
console.log(Joomla.Text('LANG_CONSTANT3', 'Default string3'));
توجه: در صورتی که کلید ترجمه اصلاً اضافه نشده باشد، مقدار پیشفرض دوم برگردانده میشود. اما اگر کلید اضافه شده ولی ترجمه نشده باشد، همان کلید دست نخورده بازگردانده میشود.
پاکسازی (Sanitize) رشتههای HTML
متد `Joomla.sanitizeHtml()` رشتههای HTML غیر قابل اعتماد را پاکسازی (sanitize) میکند و باید هر زمان که قرار است HTML از متغیرهای داینامیک، ترجمهها و ... نمایش داده شود استفاده شود.
مثال:
const myElement = document.createElement('div');
myElement.innerHTML = Joomla.sanitizeHtml(Joomla.Text('LANG_CONSTANT1', '
Default string1
'));
درخواست Ajax در جوملا
برای درخواستهای ساده GET بهتر است از تابع native fetch() مرورگر استفاده کنید.
اما اگر نیازهای بیشتری دارید مثل آپلود با نمایش پیشرفت، یا صفبندی درخواستها، جوملا تابع `Joomla.request()` را فراهم کرده است که یک wrapper روی `XMLHttpRequest` است.
تابع `Joomla.request()`
گزینههای این تابع:
- `url` (رشته) : آدرس درخواست
- `method` (رشته) : متد درخواست، به طور پیشفرض `"GET"`، میتواند `"POST"` و … باشد
- `data` : دادههای ارسالی (مثلاً فرم دیتا)
- `promise` (بولی) : اگر true باشد، یک Promise بازگردانده میشود و گزینههای perform, onSuccess, onError, onComplete نادیده گرفته میشوند
- `perform` (بولی) : اگر true باشد درخواست بلافاصله اجرا میشود، در غیر این صورت فراخوانی بعدی لازم است
- `headers` (شیء) : هدرهای سفارشی، مثلاً `{ 'X-Foo': 'Bar' }`
- `onBefore` (callback) : فراخوانی قبل از ارسال درخواست، آرگومان آن شیء XMLHttpRequest است
- `onSuccess` (callback) : فراخوانی پس از دریافت موفقیت آمیز پاسخ، آرگومانها: (response, xhr)
- `onError` (callback) : در صورت خطا در درخواست فراخوانی میشود
- `onComplete` (callback) : همیشه بعد از اتمام درخواست (با موفقیت یا خطا) فراخوانی میشود
مثال آپلود فایل با Joomla.request()
const formData = new FormData();
formData.append('file', fileBlob, filename);
Joomla.request({
url: 'index.php?option=com_example&task=upload.file',
method: 'POST',
promise: true,
data: formData,
onBefore(xhr) {
// اضافه کردن شنونده رویداد پیشرفت آپلود
xhr.upload.addEventListener('progress', (event) => {
console.log('پیشرفت آپلود:', event.loaded, 'از', event.total);
});
},
}).then((xhr) => {
console.log('فایل با موفقیت آپلود شد');
}).catch((error) => {
console.log('آپلود فایل با خطا مواجه شد');
});
- در این کد ابتدا یک شیء `FormData` ساخته میشود و فایل برای ارسال به آن اضافه میشود.
- سپس با `Joomla.request()` یک درخواست POST با `promise:true` ارسال میشود.
- در callback تابع `onBefore`، رویداد `progress` روی متد آپلود (`xhr.upload`) اضافه شده تا پیشرفت آپلود نشان داده شود.
- در صورت موفقیت پیام موفقیت در console نمایش داده میشود.
- در صورت خطا پیام خطا در console چاپ میشود.
تابع Joomla.enqueueRequest()
`Joomla.enqueueRequest()` یک صف (Queue) FIFO از درخواستهاست که درخواستها را به صورت سریالی اجرا میکند؛ این کار باعث جلوگیری از ارسال همزمان چند درخواست به سرور میشود که میتواند موجب فعال شدن مکانیزم محافظت در برابر حمله امتناع از سرویس (DoS) شود.
این صف همان گزینههایی که در `Joomla.request()` میپذیرد را دریافت میکند، با این تفاوت که الزامی است گزینه `promise:true` تنظیم شده باشد.
مثال اجرای صف درخواستها:
Joomla.request(options1);
Joomla.request(options2);
Joomla.request(options3);
در این مثال، درخواستها به ترتیب اجرا شده و پس از اتمام یک درخواست، درخواست بعدی آغاز میشود.
مثال کامل صفبندی سه درخواست Ajax
// تعریف گزینه های درخواست اول
const options1 = {
url: 'index.php?option=com_example&task=task1',
method: 'GET',
promise: true,
onSuccess(response) {
console.log('درخواست اول موفق: ', response);
},
onError(xhr) {
console.error('درخواست اول خطا: ', xhr);
}
};
// تعریف گزینه های درخواست دوم
const options2 = {
url: 'index.php?option=com_example&task=task2',
method: 'POST',
data: { param: 'value' },
promise: true,
onSuccess(response) {
console.log('درخواست دوم موفق: ', response);
},
onError(xhr) {
console.error('درخواست دوم خطا: ', xhr);
}
};
// تعریف گزینه های درخواست سوم
const options3 = {
url: 'index.php?option=com_example&task=task3',
method: 'GET',
promise: true,
onSuccess(response) {
console.log('درخواست سوم موفق: ', response);
},
onError(xhr) {
console.error('درخواست سوم خطا: ', xhr);
}
};
// صفبندی و اجرای متعاقب درخواستها
Joomla.enqueueRequest(options1);
Joomla.enqueueRequest(options2);
Joomla.enqueueRequest(options3);
توضیح نحوه عملکرد:
- با افزودن هر درخواست به `Joomla.enqueueRequest`، آن درخواست به صف اضافه میشود.
- اجرای درخواستها بر اساس ترتیب ورود انجام میشود.
- تا هنگامی که درخواست اول پایان نیابد (هم موفقیت، هم خطا)، درخواست دوم شروع نمیشود.
- همینطور درخواستهای بعدی.
نکات پیشرفته و گزینههای کاربردی:
- onBefore(xhr): میتوانید در این callback دسترسی به شیء `XMLHttpRequest` داشته باشید برای افزودن شنوندههای پیشرفت آپلود/دانلود یا تغییر هدرهای درخواست در صورت لزوم.
- cancel(): اگر بخواهید، میتوانید یک `XMLHttpRequest` را لغو کنید (مثلاً هنگام بستن پنجره یا تغییر صفحه) - در ساختار صف میتوانید این مورد را مدیریت کنید.
-headers: امکان ارسال هدرهای سفارشی برای هر درخواست، مثلاً جهت ارسال توکن امنیتی یا هدرهای مخصوص Ajax.
- پردازش پاسخها: معمولاً پاسخها را در `onSuccess` پردازش میکنید؛ اما اگر نیاز دارید پردازش پیشرفته داشتید، میتوانید از ترکیب Promises و async/await استفاده کنید.
استفاده ترکیبی با async/await
میتوانید از `Joomla.enqueueRequest()` به صورت promise و همراه async/await برای خوانایی بیشتر استفاده کنید:
async function runQueue()
{
const options = [
{ url: 'index.php?option=com_example&task=task1', method: 'GET', promise: true },
{ url: 'index.php?option=com_example&task=task2', method: 'POST', data: {foo: 'bar'}, promise: true },
{ url: 'index.php?option=com_example&task=task3', method: 'GET', promise: true }
];
for(const option of options) {
try {
const xhr = await Joomla.enqueueRequest(option);
console.log('درخواست موفق: ', xhr.responseText);
} catch(error)
}
}
اسکریپت ویرایشگرهای جوملا (Joomla Editors script)
جوملا یک API سمت کلاینت فراهم کرده است که شامل کلاسهای `JoomlaEditor` و `JoomlaEditorButton` میشود و امکان یکپارچهسازی ساده انواع ویرایشگرها (Editor) را به روشی استاندارد و هماهنگ بین افزونهها میدهد.
این API امکان برقراری ارتباط بین افزونههای مختلف جوملا و ویرایشگرها و محتوای آنها را فراهم میکند.
فعالسازی اسکریپت ویرایشگر در صفحه
برای فعال کردن این API در صفحه، از `WebAssetManager` به این شکل استفاده کنید:
$wa->useScript('editors');
این کار ماژولهای کمکی مانند `editor-api` و `editor-decorator` را نیز بارگذاری میکند.
اجزای API:
- JoomlaEditorDecorator
یک رابط (interface) مشترک برای پیادهسازی ویرایشگرها ارائه میدهد.
- JoomlaEditor
مسئول ثبت (register) و گرفتن ویرایشگر فعال (active editor) است.
- JoomlaEditorButton
مسئول ثبت دکمههای ویرایشگر و عملیات مربوط به آنها است.
این کلاسها توسط ماژول `editor-api` ارائه میشوند و میتوانید آنها را به این شکل در جاوااسکریپت وارد کنید:
import { JoomlaEditor, JoomlaEditorButton, JoomlaEditorDecorator } from 'editor-api';
نحوه عملکرد
- هر اسکریپت ویرایشگر باید نمونهی خود از `JoomlaEditorDecorator` را بسازد و کلاس مربوط به رابط `JoomlaEditorDecorator` را پیادهسازی کند و سپس با `JoomlaEditor.register(editor)` ثبت شود.
- هر زمان که کاربر با ویرایشگر یا یکی از دکمههای آن تعامل داشته باشد، ویرایشگر باید توسط `JoomlaEditor.setActive(editor)` به عنوان ویرایشگر فعال مشخص شود.
دکمههای ویرایشگر
- هر دکمه ویرایشگر ممکن است یک عملیات (action) خاص داشته باشد.
- عملیاتها باید قبلاً با `JoomlaEditorButton.registerAction(name, handler)` ثبت شوند، که:
- `name`: نام عملیات (action)
- `handler`: تابعی که هنگام اجرای آن عملیات فراخوانی میشود
- زمانی که اسکریپت ویرایشگر بخواهد دکمههای ویرایشگر را در رابط کاربریاش یکپارچه کند (مثل ادغام TinyMCE در جوملا)، مسئول است که هنگام کلیک روی دکمهی مربوطه، با تابع زیر آن عملیات را فراخوانی کند.
`JoomlaEditorButton.runAction(name, options)`
- `name`: نام عملیات برای اجرای آن
- `options`: شیء گزینههایی که به تابع عملیات پاس داده میشود
متدهای JoomlaEditor
register(editor)
ثبت یک نمونه ویرایشگر جدید که باید رابط JoomlaEditorDecorator را پیادهسازی کند.
unregister(editor)
حذف ثبت یک نمونه ویرایشگر (میتواند شیء JoomlaEditorDecorator یا شناسه آن باشد).
get(id)
دریافت نمونه ویرایشگر بر اساس شناسه، در صورتی که وجود داشت.
setActive(editor)
تعیین ویرایشگر فعال فعلی (ویرایشگری که در تمرکز است)؛ میتواند شیء ویرایشگر یا شناسه آن باشد.
getActive()
دریافت آخرین ویرایشگر فعال، در صورت وجود.
متدهای مهم JoomlaEditorButton
registerAction(name, handler)
ثبت یک عملیات (دکمه) جدید یا بازنویسی عملیات موجود که با نام مشخص ثبت شده باشد.
runAction(name, options, button)
اجرای عملیاتی که با نام مشخص ثبت شده است. پارامترهای:
name نام عملیات
options شیء گزینههایی که به handler پاس داده میشود
button (اختیاری) دکمه اجراکننده عملیات (مثلاً دکمه "دریافت اطلاعات بیشتر")
getActionHandler(name)
گرفتن تابع handler ثبت شده بر اساس نام عملیات.
نحوه تعریف یک handler برای عملیات دکمه
تابع handler یک تابع است که دو پارامتر دریافت میکند:
نمونه ویرایشگر فعال (editor) از نوع JoomlaEditorDecorator
شیء گزینههای ارسال شده هنگام اجرای عملیات (options)
مثال ثبت عملیات دکمه و اجرای آن
JoomlaEditorButton.registerAction('example', (editor, options) => {
alert('در حال انجام عملیات Example برای ویرایشگر ' + editor.getType());
});
در این مثال:
یک عملیات با نام 'example' ثبت میشود.
این عملیات تابعی را اجرا میکند که پیامی حاوی نوع ویرایشگر فعال را نمایش میدهد.
بدین ترتیب، میتوان تعامل بین افزونهها و ویرایشگرهای مختلف را استاندارد کرد و از اجرای عملیات دلخواه روی ویرایشگر در سمت کلاینت پشتیبانی نمود.
اسکریپت دیالوگ (پاپآپ) جوملا
ماژول دیالوگ جوملا قابلیت نمایش انواع پنجرههای دیالوگ (پاپآپ) را فراهم میکند.
برای افزودن ماژول دیالوگ جوملا به صفحه، از WebAssetManager به صورت زیر استفاده کنید:
$wa->useScript('joomla.dialog')
و برای فعالسازی اتصال خودکار دکمههای صفحه به این دیالوگها از این دستور استفاده کنید:
$wa->useScript('joomla.dialog-autocreate')
دیالوگ جوملا قادر است دیالوگهایی با محتوای زیر نمایش دهد:
- inline – متن یا محتوای HTML که به صورت مستقیم در صفحه است؛
- iframe– محتوای جاسازی شده یا از راه دور در فریم iframe؛
- ajax– مشابه حالت inline با این تفاوت که محتوا از طریق درخواست Ajax بارگذاری میشود؛
- image– نمایش تصویر به صورت لایتباکس؛
این ماژول همچنین متدهایی برای جایگزینی دیالوگهای استاندارد alert()و confirm() فراهم میکند. همچنین ابزاری برای متصل کردن دکمهها و لینکهای صفحه به نمایش پاپآپ بدون نیاز به کدهای جانبی اضافی ارائه میدهد.
خصوصیات
- popupType (رشته): نوع پاپآپ، مقادیر پشتیبانی شده: inline, iframe, image, ajax.
- src (رشته): مسیر منبع برای iframe، تصویر یا ajax.
- popupContent (رشته یا HTMLElement یا HTMLTemplateElement): محتوا برای پاپآپ نوع inline.
- cancelable (بولی): آیا پاپآپ با کلید Esc بسته میشود یا خیر.
- textClose (رشته): متن اختیاری برای دکمه بستن؛ وقتی دکمهای تعریف نشده باشد اعمال میشود.
- textHeader (رشته): متن اختیاری برای هدر (عنوان) پنجره.
- iconHeader (رشته): نام کلاسهای آیکون هدر.
- width (رشته): محدودیت اختیاری عرض پاپآپ، هر مقدار معتبر CSS.
- height (رشته): محدودیت اختیاری ارتفاع پاپآپ، هر مقدار معتبر CSS.
- popupTemplate (رشته یا HTMLTemplateElement): قالب برای پاپآپ.
- preferredParent (رشته یا HTMLElement): عنصری که دیالوگ به آن متصل شود؛ وقتی المان والد وجود نداشته باشد کاربرد دارد. این روش اجازه میدهد دیالوگ در همان شاخه DOM محتوا ذخیره شود.
- popupButtons (آرایه): لیست اختیاری دکمهها برای نمایش در فوتر یا هدر (یا پایین/بالای بدنه پاپآپ، وقتی هدر/فوتر وجود ندارد).
- className (رشته): کلاس CSS اختیاری برای عنصر joomla-dialog.
- data (شیء): شیء اختیاری شامل دادههای attribute برای عنصر joomla-dialog. کلیدها باید camelCase باشند. مثال: `{fooBar: 1}` معادل `data-foo-bar="1"` است.
نکته مهم
خصوصیات دیالوگ جوملا غیرقابل تغییر هستند و فقط قبل از رندر شدن میتوان آنها را تنظیم کرد. پس از آن، تغییر آنها ممکن نیست.
هر خصوصیت را میتوان به صورت مستقیم روی نمونه (instance) یا در سازنده کلاس تنظیم کرد، مانند مثالهای زیر:
// تنظیم خصوصیات در سازنده کلاس
const dialog = new JoomlaDialog({
textHeader: 'The header',
popupContent: '
متن محتوای پاپآپ
',
});
dialog.show();
// تنظیم خصوصیات پس از ایجاد نمونه کلاس
const dialog = new JoomlaDialog();
dialog.textHeader = 'The header';
dialog.popupContent = '
متن محتوای پاپآپ
';
dialog.show();
نمونه دکمهها:
dialog.popupButtons = [
{ label: 'بله', onClick: () => dialog.destroy() },
{ label: 'خیر', onClick: () => dialog.destroy(), className: 'btn btn-outline-danger ms-2' },
{ label: 'کلیک کن', onClick: () => dialog.destroy(), location: 'header' },
];
متدها
- show()
نمایش دیالوگ. در صورتی که دیالوگ قبلاً به DOM اضافه نشده باشد، آن را به DOM اضافه میکند.
- close()
بستن دیالوگ.
- destroy()
نابود کردن دیالوگ.
- getBody()
بازگرداندن عنصر بدنه دیالوگ.
- getBodyContent()
بازگرداندن عنصر محتوا. برای انواع مختلف دیالوگ، محتوا به شکلهای مختلف باز میگردد:
- برای انواع inline و ajax، popupContent باز میشود.
- برای نوع iframe، یک HTMLIframeElement باز میگردد.
- برای نوع image، یک HTMLImageElement باز میگردد.
- getHeader()
در صورت وجود، بخش هدر (سرصفحه) دیالوگ را باز میگرداند.
- getFooter()
در صورت وجود، بخش فوتر (پاصفحه) دیالوگ را باز میگرداند.
روشهای ایستا (Static methods)
- JoomlaDialog.alert(bodytext, headertext)
نمایش یک دیالوگ متنی با یک دکمه "تأیید" (Okay). این متد یک Promise برمیگرداند که هنگام بسته شدن دیالوگ توسط کاربر حل میشود.
- JoomlaDialog.confirm(bodytext, headertext)
نمایش یک دیالوگ متنی با دکمههای "بله/خیر". این متد یک Promise برمیگرداند که وقتی کاربر روی یکی از دکمهها کلیک کرد با مقدار true یا false حل میشود.
متدهای `confirm().` و `alert().` پارامتر دوم اختیاری دارند که متن هدر را مشخص میکند. در صورت حذف، متن هدر به صورت پیشفرض "Info" خواهد بود.
رویدادها
- joomla-dialog:open
هنگام باز شدن دیالوگ اتفاق میافتد.
- joomla-dialog:close
هنگام بسته شدن دیالوگ اتفاق میافتد.
- joomla-dialog:load
وقتی محتوای دیالوگ به طور کامل بارگذاری شد، این رویداد صادر میشود.
مثال کد:
const dialog = new JoomlaDialog({
popupContent: '
متن محتوای پاپآپ
',
});
dialog.addEventListener('joomla-dialog:open', () => {
console.log('دیالوگ باز شد!');
});
dialog.addEventListener('joomla-dialog:close', () => {
console.log('دیالوگ بسته شد!');
});
dialog.addEventListener('joomla-dialog:load', () => {
console.log('محتوای دیالوگ بارگذاری شد!');
});
dialog.show();
مثالهای کاربردی
فعالسازی اسکریپت
برای استفاده از امکانات دیالوگ، ابتدا اسکریپت مربوطه را با دستور زیر فعال کنید:
$wa->useScript('joomla.dialog')
وارد کردن ماژول و استفاده
import JoomlaDialog from 'joomla.dialog';
مثالهای ساخت دیالوگ
- Inline (درون صفحهای)
const dialog = new JoomlaDialog({
textHeader: 'سرصفحه',
popupContent: '
متن محتوای پاپآپ
',
});
dialog.show();
- IFrame
const dialog = new JoomlaDialog({
popupType: 'iframe',
textHeader: 'سرصفحه',
src: 'index.php?option=com_content&view=articles&tmpl=component&layout=modal',
});
dialog.show();
- Ajax
const dialog = new JoomlaDialog({
popupType: 'ajax',
textHeader: 'سرصفحه',
src: 'index.php?option=com_content&view=articles&tmpl=component&layout=modal',
});
dialog.show();
- تصویر (Image)
const dialog = new JoomlaDialog({
popupType: 'image',
src: 'images/headers/walden-pond.jpg',
});
dialog.show();
استفاده از Alert و Confirm
import JoomlaDialog from 'joomla.dialog';
// Alert
JoomlaDialog.alert('دنبال توپ کاموا دویدن، خوردن گیاهان، میو میو', 'هدر گربه')
.then(() => {
console.log('همه چیز انجام شد');
});
// Confirm
JoomlaDialog.confirm('پنیر روی تست ایردیل، شام بزرگ؟', 'هدر موش')
.then((result) => {
console.log(result ? 'تأیید شده' : 'لغو شده');
});
ایجاد خودکار دیالوگ (Auto-create)
برای نیازهای پایه، بدون نوشتن جاوااسکریپت اضافی، میتوانید از ویژگیهای دادهای دکمه یا لینک استفاده کنید. ابتدا اسکریپت را فعال کنید:
$wa->useScript('joomla.dialog-autocreate')
ویژگیهای دکمه / لینک
- `data-joomla-dialog`
مشخص میکند که این عنصر برای auto-create دیالوگ است. میتواند خالی باشد یا شامل رشته JSON با پارامترهای JoomlaDialog باشد.
- `data-joomla-dialog-cache`
اگر وجود داشته باشد، دیالوگ پس از بسته شدن نابود نمیشود و در کلیکهای بعدی همان دیالوگ باز میشود.
- `data-reload-on-close`
صفحه پس از بسته شدن دیالوگ مجدداً بارگذاری میشود.
- `data-close-on-message`
دیالوگ در صورت دریافت هر پیغام از پنجره خودش (postMessage()) بسته میشود.
- `data-checkin-url`
آدرس URL که بعد از بسته شدن دیالوگ درخواست POST به آن ارسال میشود، مناسب عملیات چکین برای ویرایش محتوا.
مثالهای Auto-create
<button class="btn btn-primary" type="button"
data-joomla-dialog='{"popupType": "iframe", "width":"80vw", "height": "80vh", "src":"index.php?option=com_content&view=articles&tmpl=component&layout=modal"}'>
کلیک
</button>
<button class="btn btn-primary" type="button"
data-joomla-dialog='{"popupType": "inline", "src":"#popupText", "width": "fit-content", "height": "fit-content"}'>کلیک</button>
<a href="/component/content?view=articles&tmpl=component&layout=modal"
data-joomla-dialog class="btn btn-outline-primary">کلیک</a>
<a href="#popupText" data-joomla-dialog class="btn btn-outline-primary">کلیک</a>
<template id="popupText"><p class="p-3">متن محتوای پاپآپ</p></template>
انتخاب محتوا (در مودال) و ارتباط بین پنجرهها
گاهی لازم است هنگام ویرایش یک محتوا، بتوان مقدار محتوای دیگری را انتخاب کرد. معمولاً این کار با استفاده از پنجره مودال (modal) انجام میشود. اما اگر محتوای مودال به شکل iframe باشد، ارتباط بین پنجرهها (cross window communication) پیچیدگیهایی دارد.
روش نادرست اما رایج
دسترسی مستقیم از iframe به والد با استفاده از
window.parent['field_id'].value = 'selected value';
روش رایجی بوده که Joomla قبلاً استفاده میکرد.
این روش ناامن، غیرقابل اطمینان و در حالتهایی که فیلد چندگانه (مثل SubForm) است کار نمیکند.
روش بهتر: ارتباط مبتنی بر پیام (postMessage)
از روش مبتنی بر پیام در جاوااسکریپت (Window.postMessage()) باید استفاده کرد که راهی امن و قابل اعتماد برای انتقال دادهها از پنجره فرزند (iframe) به پنجره والد است.
روند کار:
1. ایجادکننده (initiator) یک دیالوگ یا مودال میسازد و گوش به پیغام پیام در پنجره والد میدهد:
window.addEventListener('message', ...);
2. پنجره فرزند (iframe) پس از انتخاب کاربر، پیام با مقدارهای انتخابشده را به والد ارسال میکند:
window.parent.postMessage(...);
3. پنجره والد پیام دریافتی را پردازش، مقدارها را تنظیم، listener پیام را حذف و مودال را میبندد.
امکانات Joomla
- modal-content-select و modal-content-select-field
این دارایی ها (assets) همراه با کلاس `Joomla\CMS\Form\Field\ModalSelectField` ارائه میشوند که میتوان مستقیماً از آنها استفاده کرد یا به عنوان پایه برای فیلد خود بهره برد.
- دارایی modal-content-select-field همراه با فیلد ModalSelect بارگیری شده، هنگام درخواست دیالوگ ایجاد کرده و پیامها را دریافت میکند.
- دارایی modal-content-select که باید داخل iframe بارگذاری شود، به کلیک روی هر عنصری که صفت `data-content-select` دارد گوش میدهد و پیغام حاوی `messageType: 'joomla:content-select'` و دادههای عنصر را به والد ارسال میکند.
مثال عناصر قابل انتخاب:
<button data-content-select data-id="1" data-title="Article 1">انتخاب مقاله ۱</button>
<button data-content-select data-id="31" data-title="Article 31">انتخاب مقاله ۳۱</button>
میتوان این پیامها را برای دادههای بیشتر یا دلخواه گسترش داد.
پیامهای قابل ارسال از پنجره فرزند:
- پیام انتخاب محتوا:
window.parent.postMessage({messageType: 'joomla:content-select', id: 1, title: 'یک عنوان'});
- پیام لغو عملیات:
window.parent.postMessage({messageType: 'joomla:cancel'});
دکمههای دیالوگ و استفاده پیشرفته
توصیه میشود دکمههای تعاملی (ذخیره، لغو و ...) داخل خود دیالوگ (iframe) قرار گیرند، نه اینکه در پنجره والد رندر شوند. این کار پیچیدگی را کاهش داده و کد پایدارتر میشود.
هدایت بعد از عملیات
معمولاً کنترلر در عملیات ایجاد/ویرایش/لغو به صفحه کامل هدایت میکند. در حالت مودال، میتوان به آدرسی با `layout=modalreturn` هدایت کرد و در آنجا وضعیت نهایی را در `scriptOptions` تنظیم نمود. سپس اسکریپت `modal-content-select` آن را میخواند و نتیجه را به والد ارسال میکند.
مثال تنظیم `scriptOptions`:
$doc->addScriptOptions('content-select-on-load', [
'id' => 1,
'title' => 'یک عنوان',
]);