مدیریت منابع وب

مفهوم

در دنیای فرانت‌اند، بسیاری از منابع به هم وابسته‌اند. برای مثال، اسکریپت keepalive ما به فایل core.js برای مدیریت گزینه‌ها وابسته است. در جوملا هرگز راه ساده‌ای برای مشخص کردن این وابستگی وجود نداشت و مجبور بودید چندین فایل را به صورت جداگانه وارد کنید. از جوملا ۴ به بعد با معرفی مفهوم منابع وب این موضوع را تغییر داده است.

ممکن است مفید باشد که ویدیوی Web Asset Manager را مشاهده کنید. 

مرور کلی

مدیر منابع وب این امکان را برای شما فراهم می‌کند که به سادگی جاوااسکریپت و CSS مربوط به افزونه خود را مدیریت کنید.

نموداری که عملکرد مدیر منابع وب را برای یک کامپوننت com_example نشان می‌دهد، در تصویر زیر آمده است و این فرآیند شامل سه مرحله است که باید مدنظر قرار گیرند.

Web Asset Manager Overview

مرحله ۱: ثبت منابع (Registering Assets)

پس از راه‌اندازی اولیه و مسیردهی، جوملا می‌داند که کدام کامپوننت باید اجرا شود و مدیر منابع وب (Web Asset Manager) فایل media/<component>/joomla.asset.json را می‌خواند.

مثلاً media/com_example/joomla.asset.json.

فایل joomla.asset.json جایی است که شما:

- فایل‌های js و css کامپوننت را فهرست می‌کنید، 

- وابستگی‌های مرتبط را مشخص می‌کنید، 

- اطلاعات نسخه آن‌ها را وارد می‌کنید، 

- و هر ویژگی مرتبط (مثلاً defer، async) را ذکر می‌کنید.

جزئیات بیشتر در بخش بعدی توضیح داده شده است.

در این مرحله، مدیر منابع وب فایل joomla.asset.json کامپوننت را می‌خواند و بر اساس آن، منابع (Assets) را در رجیستری خود ایجاد می‌کند.

علاوه بر این، مدیر منابع وب فایل‌های زیر را هم می‌خواند:

- فایل سیستم: media/system/joomla.asset.json 

- فایل vendor: media/vendor/joomla.asset.json 

- فایل legacy: media/legacy/joomla.asset.json 

- و فایل قالب شما، مثلاً templates/cassiopeia/joomla.asset.json 

مرحله ۲: استفاده از منابع (Using Assets)

برای استفاده از یک منبع، از متد useScript (برای جاوااسکریپت) یا useStyle (برای CSS) در کدتان استفاده می‌کنید، مثلاً:

 
$wa = Factory::getApplication()->getDocument()->getWebAssetManager(); 
$wa->useScript('field.modal-fields');
 

 این کار باعث می‌شود که منبع در رجیستری مدیر منابع وب به عنوان "استفاده‌شده" علامت‌گذاری شود. اگر وابستگی‌هایی وجود داشته باشد، آن‌ها نیز به عنوان استفاده‌شده علامت‌گذاری می‌شوند.

در نمودار، این منابع با رنگ سبز نشان داده شده‌اند. منابع قرمز ثبت شده‌اند اما استفاده نشده‌اند.

مرحله ۳: رندر منابع (Rendering Assets)

در حالت عادی، جوملا خروجی HTML را بر اساس فایل index.php موجود در پوشه قالب شما (مثلاً /templates/cassiopeia/index.php) تولید می‌کند. اگر به این فایل نگاه کنید، مشاهده می‌کنید که در آن "جاهای خالی" وجود دارد:

 
<head>
    ...
    <jdoc:include type="styles" />
    <jdoc:include type="scripts" />
</head>
 

 جوملا این فایل HTML را تجزیه می‌کند و وقتی به این بخش‌ها می‌رسد، از مدیر منابع وب می‌خواهد که این "جاهای خالی" را با عناصر HTML مناسب مانند `<link rel="stylesheet" ...>` و `<script ...>` پر کند.

مدیر منابع وب، عناصر HTML را برای منابعی که در رجیستری آن به عنوان استفاده‌شده علامت خورده‌اند تولید می‌کند. نکته مهم این است که این مدیر وابستگی‌ها را مدنظر قرار می‌دهد، تا مطمئن شود که هر وابستگی ابتدا توسط مرورگر بارگذاری شود. ویژگی‌های مرتبط با منابع نیز به عنوان ویژگی‌های HTML اضافه می‌شوند.

همچنین مدیر منابع وب اطلاعات نسخه هر منبع را رعایت می‌کند تا اگر شماره نسخه تغییر کرد، مرورگر فایل جدید جاوااسکریپت یا CSS را از سرور درخواست کند، نه اینکه از نسخه کش‌شده استفاده کند.

توابع قدیمی (Deprecated Functions)

در گذشته افزودن فایل‌های js و css از طریق متدهایی مانند Document::addScript، Document::addStyleSheet و غیره انجام می‌شد، اما این روش‌ها حالا منسوخ شده‌اند (و قرار است در جوملا ۶ حذف شوند) و به جای آن باید از مدیر منابع وب استفاده کرد.

با این حال، متدهای Text::script و Document::addScriptOptions منسوخ نشده‌اند و همچنان باید برای ارسال رشته‌های ترجمه‌شده و متغیرها به جاوااسکریپت استفاده شوند.

تعریف

منابع مرتبط در یک فایل JSON تعریف می‌شوند مانند system/joomla.asset.json (خطوط ۱۴ تا ۲۱).

ساختار این فایل شامل یک تعریف schema (برای اعتبارسنجی)، نام، نسخه، مجوز و سپس یک یا چند تعریف منبع (asset) است. منابع شامل فهرستی از فایل‌های js و css مرتبط با آن منبع و همچنین وابستگی‌های مربوط به آن است. بخش وابستگی‌ها فقط فهرستی از نام منابعی است که برای عملکرد آن منبع لازم هستند. نمونه‌ای از یک فایل JSON به صورت زیر است:

 
{
  "$schema": "https://developer.joomla.org/schemas/json-schema/web_assets.json",
  "name": "com_example",
  "version": "4.0.0",
  "description": "Joomla CMS",
  "license": "GPL-2.0+",
  "assets": [
    {
      "name": "bar",
      "type": "style",
      "uri": "com_example/bar.css"
    },
    {
      "name": "bar",
      "type": "script",
      "uri": "com_example/bar.js"
    },
    {
      "name": "beer",
      "type": "style",
      "uri": "com_example/beer.css",
      "dependencies": [
        "bar"
      ]
    },
    {
      "name": "beer",
      "type": "script",
      "dependencies": [
        "core",
        "bar"
      ],
      "uri": "com_example/beer.js",
      "attributes": {
        "defer": true,
        "data-foo": "bar"
      }
    }
  ]
}

 

ویژگی `$schema` فایل تعریف schema است که به شما اجازه می‌دهد فایل خود را با استفاده از JSON Schema اعتبارسنجی کنید. برای کسب اطلاعات بیشتر می‌توانید وب‌سایت رسمی JSON Schema را مطالعه کنید.

توضیح اجزای اصلی فیلدهای منبع:

- `name` — این کلید منبع در رجیستری است. 

- `type` — می‌تواند "style" برای CSS ، "script" برای جاوااسکریپت یا "preset" باشد که در این حالت می‌توانید چند فایل CSS و JS را گروه‌بندی کنید (که در این صورت آن‌ها را به عنوان وابستگی با پسوند `#style` یا `#script` مشخص می‌کنید). 

- `uri` — هشدار: این ممکن است آنچه انتظار دارید نباشد! باید فایل‌های js خود را در پوشه js قرار دهید، که پس از نصب به media/com_example/js/myjsfile.js می‌رسد، اما در اینجا فقط مسیر بدون پوشه js نوشته می‌شود:

"uri": "com_example/myjsfile.js"

به همین ترتیب برای فایل‌های css که در پوشه css قرار می‌گیرند (مثلاً media/com_example/css/mycssfile.css)، پوشه css را در مسیر نمی‌نویسید:

"uri": "com_example/mycssfile.css"

مدیر منابع وب بر اساس نوع منبع، به صورت خودکار `/js` یا `/css` را به مسیر اضافه می‌کند.

- `dependencies` — آرایه‌ای از نام منابع وابسته است. 

- `attributes` — هر ویژگی‌ای که می‌خواهید به عناصر `<link>` یا `<script>` اضافه شود، اینجا تعریف می‌شود. 

وابستگی‌ها:

چگونه بدانیم دقیقاً به کدام منبع جوملا نیاز داریم؟ متأسفانه راه حل جادویی وجود ندارد و شاید لازم باشد کمی کد جوملا را بررسی کنید. برخی از وابستگی‌های رایج عبارتند از:

- `core` — کتابخانه اصلی جاوااسکریپت جوملا 

- `jquery` — کتابخانه jQuery 

- `form.validate` — برای اعتبارسنجی فرم‌ها 

- `field.modal-fields` — اگر کامپوننت شما از پنجره‌های مودال استفاده می‌کند 

یادداشت برای توسعهدهندگان

داشتن فایل joomla.asset.json برای افزونه یا قالب شما توصیه می‌شود، اما برای کارکرد WebAsset ضروری نیست (بخش بعدی را ببینید).

تذکر

اضافه کردن منابع inline (مستقیم در فایل JSON) توصیه نمی‌شود، بهتر است از فایل استفاده کنید.

توضیح مراحل منابع (Assets)

هر منبع دارای دو مرحله است: ثبت‌شده (Registered) و استفاده‌شده (Used).

مرحله ثبت‌شده (Registered)

در این مرحله، یک منبع وارد WebAssetRegistry می‌شود. یعنی WebAssetManager از وجود این منابع مطلع است، اما در هنگام رندر کردن صفحه آن‌ها را به سند HTML اضافه نمی‌کند.

تمام منابعی که از فایل joomla.asset.json بارگذاری می‌شوند، ابتدا در همین مرحله ثبت‌شده قرار می‌گیرند.

مرحله استفاده‌شده (Used)

در این مرحله، منبع از طریق متدی مثل `$wa->useAsset()` یا متدهای مشابه مانند

 
(->useScript(), ->useStyle(), ->registerAndUseX())

 

 فعال می‌شود. وقتی منبع در این مرحله قرار گیرد، WebAssetManager آن منبع و وابستگی‌هایش را به سند HTML در هنگام رندر پیوست خواهد کرد.

نکته مهم: یک منبع نمی‌تواند بدون اینکه قبلاً ثبت شده باشد، استفاده شود؛ اگر چنین اتفاقی بیفتد، خطای "asset ناشناس" رخ می‌دهد.

ثبت یک منبع (Register an asset)

تمام منابع شناخته شده بارگذاری شده و در WebAssetRegistry ذخیره می‌شوند. برای فعال یا غیرفعال کردن یک منبع، باید از WebAssetManager استفاده کنید (بخش بعدی را ببینید).

جوملا به صورت خودکار در زمان اجرا به دنبال تعریف‌های منابع در مسیرهای زیر می‌گردد و آنها را بارگذاری می‌کند (ترتیب اهمیت):

- media/vendor/joomla.asset.json (در اولین دسترسی به WebAssetRegistry) 

- media/system/joomla.asset.json 

- media/legacy/joomla.asset.json 

- media/{com_active_component}/joomla.asset.json (زمانی که برنامه dispatch می‌شود) 

- templates/{active_template}/joomla.asset.json 

و این منابع را در رجیستری منابع شناخته شده بارگذاری می‌کند.

نکته

اگر هنگام بارگذاری منابع، مدیر منابع وب منبعی با همان نام موجود در رجیستری پیدا کند، تعریف جدید جایگزین تعریف قبلی خواهد شد.

ثبت تعریف منابع خودتان

می‌توانید فایل‌های تعریف منبع اختصاصی خود را به رجیستری اضافه کنید:

 
/** @var Joomla\CMS\WebAsset\WebAssetManager $wa */
$wa = Factory::getApplication()->getDocument()->getWebAssetManager();
$wr = $wa->getRegistry();
$wr->addRegistryFile('relative/path/to/your/joomla.asset.json');

 

مثلاً برای ماژول‌ها، جوملا به صورت خودکار فایل joomla.asset.json را نمی‌خواند، اما شما می‌توانید با متد `addRegistryFile` آن را پردازش کنید.

اضافه کردن یک منبع سفارشی در زمان اجرا

با استفاده از WebAssetRegistry:

 
$wr->add('script', new Joomla\CMS\WebAsset\WebAssetItem('foobar', 'com_foobar/file.js', ['type' => 'script']));

 

یا به شکل ساده‌تر با WebAssetManager:

 
$wa->registerScript('foobar', 'com_foobar/file.js');

 

منبع جدید با نام `foobar` به رجیستری اضافه می‌شود، اما به سند متصل نمی‌گردد مگر اینکه کد شما (مثلاً در قالب یا layout) آن را درخواست کند.

بررسی وجود یک منبع

برای چک کردن اینکه یک منبع وجود دارد یا خیر:

 
if ($wa->assetExists('script', 'foobar'))
{
    var_dump('Script "foobar" exists!');
}

 

فعال‌سازی یک منبع (Asset)

مدیریت همه منابع در سند جاری `$doc` توسط کلاس WebAssetManager انجام می‌شود که می‌توانید آن را با این متد `$doc->getWebAssetManager()` دریافت کنید.

فعال کردن یک منبع در صفحه

برای فعال کردن یک منبع در صفحه، از تابع `useAsset` (و مشابه آن `useScript` یا `useStyle`) استفاده کنید، مثلاً:

 
/** @var Joomla\CMS\WebAsset\WebAssetManager $wa */
$wa = Factory::getApplication()->getDocument()->getWebAssetManager();
$wa->useScript('keepalive');
 

همچنین می‌توانید چند منبع را به صورت زنجیره‌ای فعال کنید:

 
$wa ->useScript('keepalive')
	->useScript('fields.validate')
	->useStyle('foobar')
	->useScript('foobar');

 

اگر می‌خواهید یک منبع جدید را با وابستگی تعریف و استفاده کنید، از متد `registerAndUseScript` استفاده نمایید:

 
$wa->registerAndUseScript('bar', 'com_foobar/bar.js', [], [], ['core', 'foobar']);
 

WebAssetManager بررسی می‌کند که منبع درخواست‌شده در WebAssetRegistry وجود دارد یا خیر و اگر موجود بود، آن را برای سند جاری فعال می‌کند؛ در غیر این صورت خطای `UnknownAssetException` ایجاد می‌شود.

غیرفعال کردن یک منبع در صفحه

برای غیرفعال کردن یک منبع، از تابع `disableAsset` (یا `disableScript`، `disableStyle` و ...) استفاده کنید. مثال زیر، منبع `jquery-noconflict` را غیرفعال می‌کند:

 
/** @var Joomla\CMS\WebAsset\WebAssetManager $wa */
$wa = Factory::getApplication()->getDocument()->getWebAssetManager();
$wa->disableScript('jquery-noconflict');

 

نکته: اگر منبع غیرفعال شده، وابستگی‌هایی داشته باشد که هنوز فعال هستند، آن منبع توسط WebAssetManager دوباره فعال خواهد شد، بدون توجه به غیرفعال کردن شما.

بررسی وضعیت یک منبع

برای بررسی اینکه یک منبع فعال است یا خیر (چه به صورت دستی و چه به عنوان وابستگی)، از متد `isAssetActive` استفاده کنید:

 
if ($wa->isAssetActive('script', 'foobar'))
{
    var_dump('Script "foobar" is active!');
}

 

برای دریافت وضعیت دقیق‌تر منبع، از متد `getAssetState` استفاده نمایید:

 
switch ($wa->getAssetState('script', 'foobar')) {
    case Joomla\CMS\WebAsset\WebAssetManager::ASSET_STATE_ACTIVE:
        var_dump('Active! Was enabled manually');
        break;
    case Joomla\CMS\WebAsset\WebAssetManager::ASSET_STATE_DEPENDENCY:
        var_dump('Active! Was enabled automatically while resolving dependencies');
        break;
    default:
        var_dump('Not active!');
}

 

بازنویسی (Override) یک منبع (Asset) در جوملا

گاهی لازم است تا URI (مسیر) یک منبع یا وابستگی‌های آن را بازتعریف کنید. در جوملا، فایل‌های مختلف `joomla.asset.json` به ترتیبی بارگذاری می‌شوند که تعریف‌های جدید با همان نام منبع، تعریف قبلی را بازنویسی (override) می‌کنند.

یعنی اگر در فایل `joomla.asset.json` خود، منبعی با نامی که قبلاً بارگذاری شده وجود داشته باشد، تعریف جدید جایگزین تعریف قبلی می‌شود.

همچنین می‌توانید در کد PHP با ثبت منبعی جدید با همان نام، آن را بازنویسی کنید.

مثال

فرض کنید یک منبع جاوااسکریپت با نام `"foobar"` به صورت زیر در سیستم تعریف شده است:

 
{
  "name": "foobar",
  "type": "script",
  "uri": "com_example/foobar.js",
  "dependencies": ["core"]
}

 

اما شما می‌خواهید به جای فایل محلی، نسخه CDN آن را استفاده کنید.

برای این کار کافی است در فایل `joomla.asset.json` افزونه یا قالب خود، بازتعریفی مثل زیر داشته باشید:

 
{
  "name": "foobar",
  "type": "script",
  "uri": "http://foobar.cdn.blabla/foobar.js",
  "dependencies": ["core"]
}

 

یا بازنویسی از طریق کد PHP

می‌توانید از متدهای WebAssetManager استفاده کنید تا منبع مورد نظر را با همان نام و URI جدید ثبت کنید:

 
/** @var Joomla\CMS\WebAsset\WebAssetManager $wa */
$wa = Factory::getApplication()->getDocument()->getWebAssetManager();
$wa->registerScript('foobar', 'http://foobar.cdn.blabla/foobar.js', [], [], ['core']);

 

نکته مهم

- کلید اصلی بازنویسی، نام منبع (name) است؛ اگر نام یکسان باشد، تعریف جدید اولی را جایگزین می‌کند.

- وابستگی‌ها (`dependencies`) در تعریف جدید نیز باید نگهداری شوند تا منبع به درستی اجرا شود.

- این قابلیت امکان استفاده از CDN یا نسخه‌های دلخواه اسکریپت‌ها/استایل‌ها را به راحتی فراهم می‌کند.

کار با استایل‌ها (Styles) در WebAssetManager جوملا

تعریف منابع Style در joomla.asset.json

در تعریف منابع، فایل‌های استایل با نوع `"style"` مشخص می‌شوند. مثالی از تعریف یک منبع استایل:

 
{
  "name": "foobar",
  "type": "style",
  "uri": "com_example/foobar.css"
}

 

متدهای مرتبط با مدیریت استایل در WebAssetManager

 
/** @var Joomla\CMS\WebAsset\WebAssetManager $wa */
$wa = Factory::getApplication()->getDocument()->getWebAssetManager();
// افزودن استایل به سند (فعال سازی)
$wa->useStyle('foobar');
// غیرفعال‌سازی استایل
$wa->disableStyle('foobar');
// ثبت استایل جدید بدون تعریف در فایل JSON
$wa->registerStyle('bar', 'com_example/bar.css', [], ['data-foo' => 'some attribute'], ['some.dependency']);
// استفاده از استایل ثبت‌شده
$wa->useStyle('bar');
// ثبت و فعال‌سازی همزمان استایل
$wa->registerAndUseStyle('bar', 'com_example/bar.css', [], ['data-foo' => 'some attribute'], ['some.dependency']);
 

پارامترها:

- آرایه سوم پارامترهای (options) اضافی است (اکثر مواقع خالی است). 

- آرایه چهارم صفات (attributes) اضافه‌ای مانند `data-foo="some attribute"` برای تگ `<link>` یا `<style>`. 

- آرایه پنجم وابستگی‌ها (dependencies) که این استایل به آنها وابسته است. 

 

افزودن استایل‌های inline (درون‌خطی)

WebAssetManager امکان اضافه کردن استایل‌های inline را نیز فراهم می‌کند و می‌توانید موقعیت قرارگیری آن‌ها را نسبت به منابع دیگر مشخص کنید.

روش‌هایی برای افزودن استایل inline:

 
/** @var Joomla\CMS\WebAsset\WebAssetManager $wa */
$wa = Factory::getApplication()->getDocument()->getWebAssetManager();
// افزودن یک استایل inline به صورت معمول (در انتهای همه استایل‌ها)
$wa->addInlineStyle('محتوای استایل inline1');
// افزودن استایل inline که بعد از استایل با نام "foobar" قرار می‌گیرد
$wa->addInlineStyle('محتوای inline2', ['position' => 'after'], ['data-foo' => 'bar'], ['foobar']);
// افزودن استایل inline که قبل از استایل "foobar" قرار می‌گیرد
$wa->addInlineStyle('محتوای inline3', ['position' => 'before'], [], ['foobar']);
// افزودن استایل inline با نام مشخص
$wa->addInlineStyle('محتوای inline4', ['name' => 'my.inline.asset']);
 

 - پارامتر اول: محتوای CSS به صورت رشته است. 

- پارامتر دوم: گزینه‌ها (options)، مثلاً `'position'` که می‌تواند `'before'` یا `'after'` باشد. 

- پارامتر سوم: صفات تگ مانند `data-foo`. 

- پارامتر چهارم: آرایه وابستگی‌ها (نام منابع استایل که این inline نسبت به آنها موقعیت‌گذاری می‌شود). 

توجه مهم

- استایلی که به عنوان وابستگی در نظر گرفته شده (`'foobar'` در مثال‌ها) باید در رجیستری منابع وجود داشته باشد؛ وگرنه خطا‌ی unsatisfied dependency خواهید گرفت. 

- اگر یک استایل inline به چند منبع وابسته باشد، موقعیت نسبت به آخرین وابستگی تعیین می‌شود:

 
$wa->addInlineStyle('content inline1', ['position' => 'before'], [], ['foo', 'bar']); 
$wa->addInlineStyle('content inline2', ['position' => 'after'], [], ['foo', 'bar']);

 

خروجی:

 
<link rel="stylesheet" href="/foo.css" />
<style>content inline1</style>
<link rel="stylesheet" href="/bar.css" />
<style>content inline2</style>
 

 نکته درباره وابستگیهای استایلهای inline

- استایل‌های inline می‌توانند به استایل‌های inline دیگر وابستگی داشته باشند (با نام‌گذاری). 

- اما توصیه نمی‌شود که استایل inline به استایل غیر-inline وابسته باشد. اگرچه ممکن است فعلاً کار کند، این رفتار احتمالاً در آینده تغییر خواهد کرد. توصیه اصلی استفاده از گزینه `'position'` برای کنترل ترتیب است.

کار با اسکریپت‌ها (Scripts) در WebAssetManager جوملا

تعریف منابع Script در joomla.asset.json

آیتم‌های اسکریپت نوع `"script"` دارند. نمونه تعریف یک اسکریپت ساده:

 
{
  "name": "foobar",
  "type": "script",
  "uri": "com_example/foobar.js",
  "dependencies": ["core"]
}

 

نمونه تعریف اسکریپت با ماژول ES6 و fallback به نسخه legacy:

 
{
  "name": "foobar-legacy",
  "type": "script",
  "uri": "com_example/foobar-as5.js",
  "attributes": {
    "nomodule": true,
    "defer": true
  },
  "dependencies": ["core"]
},
{
  "name": "foobar",
  "type": "script",
  "uri": "com_example/foobar.js",
  "attributes": {
    "type": "module"
  },
  "dependencies": [
    "core",
    "foobar-legacy"
  ]
}

 

متدهای مرتبط با مدیریت اسکریپت در WebAssetManager

 
/** @var Joomla\CMS\WebAsset\WebAssetManager $wa */
$wa = Factory::getApplication()->getDocument()->getWebAssetManager();
// فعال کردن اسکریپت foobar برای صفحه
$wa->useScript('foobar');
// غیرفعال‌سازی اسکریپت foobar
$wa->disableScript('foobar');
// ثبت اسکریپت جدید بدون تعریف در فایل JSON
$wa->registerScript('bar', 'com_example/bar.js', [], ['defer' => true], ['core']);
// استفاده از اسکریپت ثبت‌شده
$wa->useScript('bar');
// ثبت و فعال‌سازی همزمان اسکریپت
$wa->registerAndUseScript('bar', 'com_example/bar.js', [], ['defer' => true], ['core']);

 

توضیح پارامترهای متدها:

- آرایه سوم: options اضافی (معمولاً خالی). 

- آرایه چهارم: attributes (ویژگی‌های تگ `<script>` مثلاً `defer`, `type` و غیره). 

- آرایه پنجم: وابستگی‌های اسکریپت. 

افزودن اسکریپت‌های inline (درون‌خطی)

امکان افزودن اسکریپت inline به همراه کنترل موقعیت نسبت به سایر اسکریپت‌ها فراهم است:

 
/** @var Joomla\CMS\WebAsset\WebAssetManager $wa */
$wa = Factory::getApplication()->getDocument()->getWebAssetManager();
// افزودن اسکریپت inline در انتهای همه اسکریپت‌ها
$wa->addInlineScript('محتوای inline1');
// افزودن اسکریپت inline که بعد از اسکریپت "foobar" قرار می‌گیرد
$wa->addInlineScript('محتوای inline2', ['position' => 'after'], ['data-foo' => 'bar'], ['foobar']);
// افزودن اسکریپت inline که قبل از اسکریپت "foobar" قرار می‌گیرد
$wa->addInlineScript('محتوای inline3', ['position' => 'before'], [], ['foobar']);
// اسکریپت inline با نام مشخص
$wa->addInlineScript('محتوای inline4', ['name' => 'my.inline.asset']);
// تعیین نوع اسکریپت (مثلاً module)
$wa->addInlineScript('محتوای inline5', [], ['type' => 'module']);

 

پارامترهای این متد:

- پارامتر اول: محتوای کد اسکریپت. 

- پارامتر دوم: تنظیمات، برای تعیین موقعیت (`position` با مقادیر `before` یا `after` معمول است) و نام (name). 

- پارامتر سوم: صفات تگ `<script>`. 

- پارامتر چهارم: وابستگی‌ها (اسکریپت‌هایی که این inline نسبت به آن‌ها موقعیت قرارگیری دارد). 

نکات مهم

- اسکریپتی که به عنوان وابستگی تعیین شده (`foobar` در مثال‌ها) باید در رجیستری منابع موجود باشد، در غیر این صورت خطای `unsatisfied dependency` رخ می‌دهد. 

- اگر به یک اسکریپت inline، چند وابستگی داده شود، موقعیت آن نسبت به **آخرین وابستگی** مشخص می‌شود؛ مثال:

 
$wa->addInlineScript('content of inline1', ['position' => 'before'], [], ['foo', 'bar']);
$wa->addInlineScript('content of inline2', ['position' => 'after'], [], ['foo', 'bar']);

 

تولید خواهد کرد:

 
...
<script src="/foo.js"></script>
<script>content of inline1</script>
<script src="/bar.js"></script>
<script>content of inline2</script>
...

 

نکته

یک منبع درون‌خطی نامگذاری‌شده ممکن است به یک منبع درون‌خطی دیگر وابسته باشد، با این حال توصیه نمی‌شود از یک منبع درون‌خطی به عنوان وابستگی به منبع غیر درون‌خطی استفاده شود. این روش جواب می‌دهد، اما این رفتار ممکن است در آینده تغییر کند. توصیه می‌شود به جای آن از "position" استفاده کنید.

کار با ESM Importmap در WebAssetManager جوملا

جوملا با WebAssetManager امکان تعریف importmap برای ماژول‌های ES (ES Modules) را فراهم کرده است.

تعریف منبع اسکریپت به عنوان Importmap

برای اینکه یک منبع اسکریپت به importmap اضافه شود، باید گزینه `"importmap": true` را در تعریف منبع قرار دهید. در کنار آن گزینه‌های دیگری هم وجود دارد:

- importmap (boolean): مشخص می‌کند که این منبع باید در importmap قرار بگیرد یا خیر. 

- importmapName (string، اختیاری): نام ماژولی که در importmap ثبت می‌شود. 

  - مثال: اگر نام منبع `foo` است و می‌خواهید نام ماژول در importmap به صورت `@foo` باشد، این مقدار را `@foo` قرار دهید. 

- importmapScope (string، اختیاری): مسیر مبنایی (scope) برای این منبع در importmap.

نمونه تعریف JSON یک منبع Importmap

 
{
  "name": "foo",
  "type": "script",
  "uri": "media/foo/module.js",
  "importmap": true,
  "importmapName": "@foo",
  "importmapScope": "/app/"
}

 

استفاده از متدهای WebAssetManager برای Importmap

تمام متدهایی که برای کار با اسکریپت‌ها وجود دارد (`useScript()`, `registerScript()`, `registerAndUseScript()` و غیره)، برای منابع Importmap نیز همانند اسکریپت‌های عادی استفاده می‌شوند.

نکته مهم

- WebAssetManager به طور خودکار هنگام رندر صفحه، تگ `<script type="importmap">` مناسب را ایجاد می‌کند و منابع تعریف‌شده با `"importmap": true` را در آن قرار می‌دهد. 

- وابستگی‌ها و ترتیب بارگذاری نیز به صورت خودکار مدیریت می‌شود.

کار با وب کامپوننت‌ها (Web Components) در جوملا

جوملا امکان استفاده از Web Componentsرا به شما می‌دهد. بارگذاری وب کامپوننت‌ها در جوملا متفاوت از اسکریپت‌های معمولی است؛ این منابع توسط Web Component Loader بارگذاری می‌شوند و به صورت **آسنکرون** (asynchronously) لود خواهند شد.

از نظر استفاده در WebAssetManager، کار با وب کامپوننت‌ها همانند اسکریپت‌ها (script asset item) است.

مثال تعریف وب کامپوننت در joomla.asset.json (به صورت ES6 module):

 
{
  "name": "webcomponent.foobar",
  "type": "style",
  "uri": "com_example/foobar-custom-element.css"
},
{
  "name": "webcomponent.foobar",
  "type": "script",
  "uri": "com_example/foobar-custom-element.js",
  "attributes": {
    "type": "module"
  }
}

 

مثال با fallback برای مرورگرهای بدون پشتیبانی ES6 module:

 نکته مهم: اسکریپت legacy باید وابستگی `wcpolyfill` داشته باشد و اسکریپت مدرن ماژول باید وابسته به همان legacy باشد.

 
{
  "name": "webcomponent.foobar",
  "type": "style",
  "uri": "com_example/foobar-custom-element.css"
},
{
  "name": "webcomponent.foobar-legacy",
  "type": "script",
  "uri": "com_example/foobar-custom-element-es5.js",
  "attributes": {
    "nomodule": true,
    "defer": true
  },
  "dependencies": [
    "wcpolyfill"
  ]
},
{
  "name": "webcomponent.foobar",
  "type": "script",
  "uri": "com_example/foobar-custom-element.js",
  "attributes": {
    "type": "module"
  },
  "dependencies": [
    "webcomponent.foobar-legacy"
  ]
}

 

ثبت وب کامپوننت‌ها در PHP

 
/** @var Joomla\CMS\WebAsset\WebAssetManager $wa */
$wa = Factory::getApplication()->getDocument()->getWebAssetManager();

$wa->registerStyle('webcomponent.foobar', 'com_example/foobar-custom-element.css')
   ->registerScript('webcomponent.foobar', 'com_example/foobar-custom-element.js', ['type' => 'module']);

 

فعال سازی وب کامپوننت در سند جاری

 
$wa->useStyle('webcomponent.foobar') ->useScript('webcomponent.foobar');

 

نکات مهم

- بهتر است برای نامگذاری وب کامپوننت‌ها از پیشوند `webcomponent.` استفاده کنید تا به راحتی قابل تشخیص باشند و با اسکریپت‌های معمولی اشتباه نشوند. 

- متدهای کار با وب کامپوننت همانند متدهای مربوط به اسکریپت‌ها هستند. 

- بارگذاری وب کامپوننت‌ها به صورت آسنکرون توسط Web Component Loader انجام می‌شود.

کار با Presets در WebAssetManager جوملا

Preset نوع خاصی از آیتم‌های Asset است که شامل یک **لیست از آیتم‌ها** با انواع مختلف (اسکریپت، استایل، حتی پرست‌های دیگر و ...) می‌باشد. استفاده از Preset مانند فراخوانی متوالی `useAsset()` روی هر آیتم لیست است.

ساختار تعریف Preset در joomla.asset.json

- نوع (`type`) باید `preset` باشد. 

- در بخش `dependencies` لیستی از آیتم‌ها (assets) قرار می‌گیرد که به شکل `assetName#type` تنظیم شده‌اند. 

- `type` بعد از علامت `#` مشخص می‌شود تا نوع هر آیتم (مثلاً `style` یا `script`) معین باشد.

مثال:

 
{
  "name": "foobar",
  "type": "preset",
  "uri": "",
  "dependencies": [
    "core#script",
    "foobar#style",
    "foobar#script"
  ]
}

 

متدهای کار با Preset

 
/** @var Joomla\CMS\WebAsset\WebAssetManager $wa */
$wa = Factory::getApplication()->getDocument()->getWebAssetManager();
// فعال‌سازی همه آیتم‌های پرست foobar
$wa->usePreset('foobar');
// غیرفعال‌سازی همه آیتم‌های پرست foobar
$wa->disablePreset('foobar');
// ثبت پرست جدید بدون تعریف در فایل JSON
$wa->registerPreset('bar', '', [], [], ['core#script', 'bar#script']);
// استفاده از پرست ثبت‌شده
$wa->usePreset('bar');
// ثبت و فعال‌سازی یک پرست در یک مرحله
$wa->registerAndUsePreset('bar', '', [], [], ['core#script', 'bar#script']);

 

پارامترهای متد `registerPreset` و `registerAndUsePreset` مشابه دیگر موارد است:

- نام پریست 

- uri که معمولاً خالی است (چون خود پرست فایل مستقلی ندارد) 

- آرایه option و attributes (اغلب خالی) 

- آرایه وابستگی‌ها که همان لیست آیتم‌ها به شکل `name#type` است

نکات مهم

- Preset قابلیتی است برای گروه‌بندی منابع (اسکریپت‌ها، استایل‌ها و پرست‌های دیگر) و فعال/غیرفعال‌سازی گروهی آن‌ها. 

- در وابستگی‌ها باید نوع asset مشخص شود (`style`, `script`, `preset` و ...). 

- استفاده از Preset سرعت مدیریت و سازماندهی وابستگی‌ها را بالا می‌برد.

تعریف و استفاده از کلاس سفارشیWebAssetItem در جوملا

جوملا به صورت پیش‌فرض از کلاس `Joomla\CMS\WebAsset\WebAssetItem` برای تمام آیتم‌های asset استفاده می‌کند، اما شما می‌توانید کلاس‌های سفارشی خود را برای مدیریت بهتر و انجام عملیات پیشرفته تعریف کنید.

۱. تعریف کلاس سفارشی برای WebAssetItem

کلاس شما باید یکی از دو شرایط زیر را داشته باشد:

- از کلاس `WebAssetItem` ارث‌بری کند:

 
use Joomla\CMS\WebAsset\WebAssetItem;
use Joomla\CMS\Factory;
class MyComExampleAssetItem extends WebAssetItem
{
    public function getUri($resolvePath = true): string
    {
        $langTag = Factory::getApplication()->getLanguage()->getTag();
        // برای اسکریپت از پسوند .js استفاده کنید
        $path    = 'com_example/bar-' . $langTag . '.js';

        if ($resolvePath)
        {
            // برای اسکریپت نوع مسیر "script" است
            $path = $this->resolvePath($path, 'script');
        }

        return $path;
    }
}

 

- یا اینترفیس `WebAssetItemInterface` را پیاده‌سازی کند.

۲. پیاده‌سازی `WebAssetAttachBehaviorInterface` برای رفتار سفارشی هنگام attach شدن به Document

اگر بخواهید هنگام فعال شدن asset، کاری مثل افزودن گزینه‌های اسکریپت انجام دهید:

 
use Joomla\CMS\WebAsset\WebAssetItem;
use Joomla\CMS\WebAsset\WebAssetAttachBehaviorInterface;
use Joomla\CMS\Factory;
use Joomla\CMS\Document\HtmlDocument;

class MyFancyFoobarAssetItem extends WebAssetItem implements WebAssetAttachBehaviorInterface
{
    public function onAttachCallback(HtmlDocument $doc): void
    {
        $user = Factory::getApplication()->getIdentity();
        $doc->addScriptOptions('com_example.fancyfoobar', ['userName' => $user->username]);
    }
}

 

نکته مهم: این asset باید قبل از رویداد `onBeforeCompileHead` فعال شده باشد تا متد `onAttachCallback` فراخوانی شود.

۳. تعریف کلاس سفارشی در فایل `joomla.asset.json`

می‌توانید کلاس و فضای نام (namespace) را در سطح root یا در هر آیتم جداگانه مشخص کنید.

مثال کامل:

 
{
  "$schema": "https://developer.joomla.org/schemas/json-schema/web_assets.json",
  "name": "com_example",
  "version": "4.0.0",
  "namespace": "Joomla\\Component\\Example\\WebAsset",
  "assets": [
    {
      "name": "foo",
      "type": "script",
      "class": "FooAssetItem",
      "uri": "com_example/foo.js"
    },
    {
      "name": "bar",
      "type": "script",
      "namespace": "MyFooBar\\Library\\Example\\WebAsset",
      "class": "BarAssetItem",
      "uri": "com_example/bar.js"
    }
  ]
}

 

- آیتم `foo` کلاس `Joomla\Component\Example\WebAsset\FooAssetItem` را خواهد داشت. 

- آیتم `bar` کلاس `MyFooBar\Library\Example\WebAsset\BarAssetItem` را خواهد داشت.

نکته در مورد namespace

- اگر فضای نام (`namespace`) تعریف نشود، پیش‌فرض `Joomla\CMS\WebAsset` استفاده می‌شود. 

- اگر `namespace` به صورت خالی تعریف شود (`""`)، فضای نام نادیده گرفته و فقط کلاس مورد استفاده قرار می‌گیرد:

 
{
  "assets": [
    {
      "name": "foo",
      "type": "script",
      "class": "FooAssetItem",
      "uri": "com_example/foo.js"
    },
    {
      "name": "bar",
      "type": "script",
      "namespace": "",
      "class": "BarAssetItem",
      "uri": "com_example/bar.js"
    }
  ]
}

 

- در این مثال کلاس آیتم `foo` `Joomla\CMS\WebAsset\FooAssetItem` است. 

- کلاس آیتم `bar`: به صورت `BarAssetItem` (بدون namespace) استفاده می‌شود.

جمع‌بندی

- با تعریف کلاس سفارشی برای آیتم‌های WebAsset، می‌توانید رفتارهای پیشرفته مثل تغییر داینامیک مسیر فایل‌ها یا افزودن گزینه‌ها هنگام بارگذاری اسکریپت‌ها را پیاده‌سازی کنید. 

- کلاس سفارشی باید از `WebAssetItem` ارث‌بری کند یا اینترفیس `WebAssetItemInterface` را پیاده‌سازی نماید. 

- برای اجرای عملیاتی هنگام attach شدن asset به سند، می‌توانید اینترفیس `WebAssetAttachBehaviorInterface` را نیز پیاده‌سازی کنید. 

- تنظیم نام کلاس و فضای نام (Namespace) در فایل `joomla.asset.json` امکان‌پذیر است تا جوملا هنگام بارگذاری asset به جای کلاس پیش‌فرض از کلاس‌های شما استفاده کند. 

- اگر فضای نام تعریف نشود، پیش‌فرض فضای نام `Joomla\CMS\WebAsset` است و در صورت تعریف namespace به عنوان رشته خالی، فقط نام کلاس بدون فضای نام استفاده می‌شود. 

- استفاده از کلاس‌های سفارشی به شما کنترل بیشتری روی مدیریت و رفتار asset‌ها در جوملا می‌دهد.