Manual:Etiket uzantıları

From mediawiki.org
This page is a translated version of the page Manual:Tag extensions and the translation is 100% complete.
MediaWiki uzantıları

Bireysel projeler, ister basit dize işleme ister tam gelişmiş bilgi alma olsun, ek yeteneklerle yerleşik viki işaretlemesini genişletmeyi yararlı bulacaktır. Etiket uzantıları, kullanıcıların tam da bunu yapan yeni özel etiketler oluşturmasına olanak tanır. Örneğin, sayfaya bir bağış formu ekleyen basit bir ‎<donation /> etiketi eklemek için bir etiket uzantısı kullanılabilir. Ayrıştırıcı işlevleri ve kancalar ile birlikte uzantılar, MediaWiki'nin işlevselliğini değiştirmenin veya geliştirmenin en etkili yoludur. Bir uzantı üzerinde çalışmaya başlamadan önce, yapmaya çalıştığınız şeyi başka birinin tam olarak yapmadığından emin olmak için her zaman kontrol etmelisiniz.

Basit bir etiket uzantısı, ayrıştırıcıya kancalı olan bir geri çağrı işlevinden oluşur, böylece ayrıştırıcı çalıştığında, tüm öğeleri bulup değiştirir. Gerçek HTML'yi oluşturmak için ilgili geri çağırma işlevini çağıran belirli bir etiketin örnekleri.

Örnek

In extension.json, set up the hooks:

...
  "Hooks": {
    "ParserFirstCallInit": "ExampleExtension::onParserFirstCallInit"
   },
...

And add the hook into a PHP file

<?php

class ExampleExtension {
	// Ayrıştırıcı ile herhangi bir işleme geri çağırmasını kaydedin
	public static function onParserFirstCallInit( Parser $parser ) {
		// Ayrıştırıcı <sample> etiketini gördüğünde, renderTagSample ile yürütür (aşağıya bakın)
		$parser->setHook( 'sample', [ self::class, 'renderTagSample' ] );
	}

	// Render <sample>
	public static function renderTagSample( $input, array $args, Parser $parser, PPFrame $frame ) {
		// Burada heyecan verici bir şey yok, sadece kullanıcı tarafından sağlanan girdiden kaçın ve tekrar dışarı atın (örnek olarak)
		return htmlspecialchars( $input );
	}
}

Bu örnek, ‎<sample> etiketi için bir geri çağrı işlevi kaydeder. Bir kullanıcı bu etiketi şöyle bir sayfaya eklediğinde: <sample arg1="xxx" arg2="xxx">...input...</sample>, ayrıştırıcı dört bağımsız değişken ileterek renderTagSample() işlevini çağırır:

$input
‎<sample> ve ‎</sample> etiketleri arasında giriş yapın veya etiket "kapalı" ise null, yani ‎<sample />
$args
HTML etiketi öznitelikleri gibi girilen etiket bağımsız değişkenler; bu, öznitelik adına göre indekslenmiş bir ilişkisel dizidir.
$parser
Üst ayrıştırıcı (bir Parser nesnesi); daha gelişmiş uzantılar, bağlamsal Title elde etmek, viki metnini ayrıştırmak, parantezleri genişletmek, bağlantı ilişkilerini ve bağımlılıkları kaydetmek vb. için bunu kullanır.
$frame
Üst çerçeve (bir PPFrame nesnesi). Bu, uzantının çağrıldığı bağlam hakkında ayrıştırıcıya daha eksiksiz bilgi sağlamak için $parser ile birlikte kullanılır.

Daha ayrıntılı bir örnek için Etiket uzantısı örneği bakın

Öznitellikler

Başka bir örneğe bakalım:

<?php

$wgHooks['ParserFirstCallInit'][] = 'onParserFirstCallInit';

function onParserFirstCallInit( Parser $parser ) {
	$parser->setHook( 'sample', 'wfSampleRender' );
}

function wfSampleRender( $input, array $args, Parser $parser, PPFrame $frame ) {
	$attr = [];    
	// Bu sefer, özniteliklerin ve değerlerinin bir listesini yapın ve bunları kullanıcı girişiyle birlikte boşaltın.
	foreach( $args as $name => $value ) {
		$attr[] = '<strong>' . htmlspecialchars( $name ) . '</strong> = ' . htmlspecialchars( $value );
	}
	return implode( '<br />', $attr ) . "\n\n" . htmlspecialchars( $input );

/**
 * Değişken değerlerini doğrudan almak için aşağıdaki satırlar kullanılabilir:
 * $to = $args['to'] ;
 * $email = $args['email'] ;
 */
}

Bu örnek, etikete iletilen öznitelikleri değerleriyle birlikte atar. Bunun yeni, özel etiketlerin esnek bir şekilde belirtilmesine izin verdiği oldukça açıktır. Örneğin, bir kullanıcının <emailform to="User" email="user@foo.com" /> gibi bir şey kullanarak kullanıcı sayfasına bir iletişim formu eklemesine izin veren bir etiket uzantısı tanımlayabilirsiniz.

MediaWiki için gerçek anlamda çok sayıda etiket uzantısı mevcuttur, bunlardan bazıları bu sitede listelenmiştir; diğerleri hızlı bir web aramasıyla bulunabilir. Bunların birçoğu kullanım durumları için oldukça uzmanlaşmış olsa da, değişen derecelerde işlevsellik sağlayan çok sayıda sevilen ve kullanılan uzantılar vardır.

Sözleşmeler

Bir uzantının genel düzeni ve kurulumu için Manual:Developing extensions sayfasına bakın.

Uzantılarınızı yayımlama

  1. Bu vikide uzantınız, nasıl kurulacağı ve kullanımdaki ekran görüntüleri hakkında bilgiler içeren Extension:<uzantı_adı> adlı yeni bir sayfa oluşturun. Template:Extension adlı bu bilgiyi tutmak için uygun bir şablon oluşturuldu. Daha fazla bilgi için şablon sayfasına bakın. Ayrıca sayfanın gövdesine mümkün olduğunca fazla ayrıntı eklemelisiniz ve ilgili tartışma sayfasındaki kullanıcı sorularına yanıt vermek için oldukça düzenli olarak tekrar kontrol etmek akıllıca olacaktır. Ayrıca sayfanın Kategori:Uzantılar ile ait olduğundan emin olun.
  2. Uzantı kodu içinde yeni kancalar oluşturan uzantılar, onları uzantı kancası kaydına kaydetmelidir.
  3. mediawiki-l posta listesine bildirin.

Ayrıca uzantınızı yayımlama bölümüne bakın.

SSS

Güvenlik endişeleri

Yukarıda, yukarıdaki örneklerdeki girişinin, döndürülmeden önce htmlspecialchars() kullanılarak kaçıldığını fark edeceksiniz. İsteğe bağlı HTML yerleştirme için vektörleri tanıtmaktan kaçınmak için, tüm kullanıcı girdilerinin istemcilere geri yansıtılmadan önce bu şekilde ele alınması hayati önem taşır, bu da siteler arası betik çalıştırma güvenlik açıkları oluşturmaya neden olabilir.

Yükleme modülleri

Uzantınız için modül eklemenin doğru yolu, onları $wgOut yerine ParserOutput ile eklemektir. Modül listesi daha sonra otomatik olarak ParserOutput nesnesinden alınacak ve sayfa işleme önceden önbelleğe alınmış olsa bile $wgOut ile eklenecektir. Modülleri doğrudan $wgOut ile ekliyorsanız, bunlar ayrıştırıcı çıkışında önbelleğe alınmamış olabilir.

function myCoolHook( $text, array $params, Parser $parser, PPFrame $frame ) {
	// ... do stuff ...
	$parser->getOutput()->addModules( 'ext.mycoolext' );
	$parser->getOutput()->addModuleStyles( 'ext.mycoolext.styles' );
	// ... do more stuff ...
}

Zamanlama ve uzantılar

Bir uzantının kodunu değiştirirseniz, uzantıyı kullanan tüm sayfalar teorik olarak yeni kodun sonuçlarını hemen yansıtır. Teknik olarak, bu, uzantıyı içeren bir sayfa her oluşturulduğunda kodunuzun yürütüldüğü anlamına gelir.

Uygulamada, MediaWiki yazılımı, tarayıcı veya bir aracı proxy veya güvenlik duvarı tarafından sayfa önbelleğe alma nedeniyle bu genellikle böyle değildir.

MediaWiki'nin ayrıştırıcı önbelleğini atlamak ve sayfanın yeni bir sürümünün oluşturulduğundan emin olmak için, Düzenle düğmesine tıklayın, tarayıcınızın adres çubuğunda gösterilen URL'deki "action=edit" olarak "action=purge" ile değiştirin ve yeni URL'yi gönderin. Sayfa ve kaynak verdiği tüm şablonlar, önbelleğe alınmış tüm veriler yok sayılarak yeniden oluşturulacaktır. Ana sayfanın kendisi değiştirilmediyse, ancak oluşturulma şekli değiştiyse (uzantı değiştirildi veya yalnızca başvurulan bir şablon değiştirildiyse) temizleme eylemi gereklidir.

Bu size sayfanın yeni bir kopyasını almak için yeterli değilse, normalde yukarıdaki URL'nin sonuna '&rand=somerandomtext' ekleyerek aracı önbellekleri atlayabilirsiniz. Her seferinde 'somerandomtext' farklı olduğundan emin olun.

Uzantımı kullanan sayfalar için önbelleğe almayı nasıl devre dışı bırakırım?

MediaWiki 1.5'ten beri, ayrıştırıcı bir uzantıya üçüncü parametre olarak geçirilir. Bu ayrıştırıcı, önbelleği şu şekilde geçersiz kılmak için kullanılabilir:

function wfSampleSomeHookFunction( $text, array $args, Parser $parser, PPFrame $frame ) {
	$parser->disableCache();
	// ...
}

Başka bir sayfa düzenlendiğinde sayfayı yeniden oluşturma

Belki de önbelleğe almayı tamamen devre dışı bırakmak istemiyorsunuz, yalnızca başka bir sayfa düzenlendiğinde sayfanın yeniden oluşturulmasını istiyorsunuz, tıpkı şablon yansıtmaların işlenme şekline benzer şekilde. Bu, kanca işlevinize iletilen ayrıştırıcı nesne kullanılarak yapılabilir. Aşağıdaki yöntem CoreParserFunctions.php dosyasından kaldırıldı ve bu amaç için çalışıyor gibi görünüyor.

/** Make the page being parsed have a dependency on $page via the templatelinks table. 
*/
function wfSampleaddTemplateLinkDependency( Parser $parser, $page )  {
	$title = Title::newFromText( $page );
	$rev = Revision::newFromTitle( $title );
	$id = $rev ? $rev->getPage() : 0;
	// Register dependency in templatelinks
	$parser->getOutput()->addTemplate( $title, $id, $rev ? $rev->getId() : 0 );
}

Önbelleğe alma davranışının ince taneli ayarı

Uzantı çıkışınızın farklı sürümlerini ayırt etmek için önbellek anahtarlarını kullanarak uzantınız için ayrıntılı önbelleğe almayı kullanabilirsiniz. Oluştururken, kanca işlevinize bir addExtraKey yöntemi ekleyerek her özellik için önbellek anahtarları ekleyebilirsiniz, örneğin:

function wfSampleSomeHookFunction( $text, array $args, Parser $parser, PPFrame $frame ) {
	$setting1= (int) $parser->getUser()->getOption('setting1');
	$parser->getOptions()->optionUsed( 'setting1' );
	$setting2= (int) $parser->getUser()->getOption('setting2');
	$parser->getOptions()->optionUsed( 'setting2' );
	...
}

Ancak, ayrıştırma sırasında $parser->getOptions() ögesinin değiştirilmesi, önbelleğe alınmış bir sayfa almaya çalışırken fazladan seçenek anahtarlarının eklenmediği, yalnızca önbelleğe alınacak bir sayfa oluşturulurken eklendiği anlamına gelir, böylece PageRenderingHash ek seçenekleri ayarlamak için kanca ögesini kullanabilirsiniz. PageRenderingHash, hem bir sayfa önbelleğe alınırken hem de çıkarılırken çalıştırılır, bu nedenle, henüz orada değilse, karmaya yalnızca yeni anahtarlar eklemek önemlidir. ör.:

$wgHooks['PageRenderingHash'][] = 'wfMyExtOnPageRenderingHash';

function wfMyExtOnPageRenderingHash( &$confstr, $user, $optionsUsed ) {
	if ( in_array( 'setting1', $optionsUsed ) ) {
		$confstr .= "!setting1=" . $user->getOption('setting1');
	}
	if ( in_array( 'setting2', $optionsUsed ) ) {
		$confstr .= "!setting2=" . $user->getOption('setting2');
	}
}

Bununla ilgili bazı önemli notlar:

  • Konfstr'de yalnızca "!$value" yerine "!setting1=$value" kullanılması, farklı uzantılar yüklendiğinde veya yükleme sırası değiştiğinde ayrıştırıcı önbelleğinin bozulmamasını sağlar. ! farklı işleme seçenekleri için bir ayırıcı olarak kullanılır
  • Bazı kişiler $parser->getOptions()->optionUsed() yerine $parser->getOptions()->addExtraKey() kullanır. addExtraKey ögenin ayrıştırıcı önbelleğine ekstra anahtarın kullanımda olduğunu söylemediği konusunda uyarılırsınız ve bu nedenle, dikkatli olmazsanız kolayca önbelleğin bozulmasına neden olabilir.

Uzantımda vikimetni nasıl oluştururum?

1.16 sürümünden beri

MediaWiki sürümü:
1.16

Ayrıştırıcı kanca işlevleri, ayrıştırıcı nesnesine ve bir çerçeve nesnesine bir kaynak iletilir; bunlar vikimetinin ayrıştırmak için kullanılmalıdır.

function wfSampleWonderfulHook( $text, array $args, Parser $parser, PPFrame $frame ) {
	$output = $parser->recursiveTagParse( $text, $frame );
	return '<div class="wonderful">' . $output . '</div>';
}

Parser::recursiveTagParse() 1.8 sürümünden beri kullanılmaktadır. Avantajları arasında basitlik (yalnızca bir bağımsız değişken alır ve bir dize döndürür) ve uzantı etiketlerini $text içinde ayrıştırması ve böylece uzantı etiketlerini iç içe geçirmeniz yer alır.

recursiveTagParse için ikinci parametre olan $frame, MW 1.16 alpha'da (r55682) sunulan isteğe bağlı bir bağımsız değikendir.

  • $frame sağlanırsa (uzantınıza iletilen $frame değeri kullanılarak), $text içindeki tüm şablon parametreleri genişletilecektir. Diğer bir deyişle, {{{1}}} gibi içerik tanınır ve uygun değere dönüştürülür.
  • $frame sağlanmazsa (ör. $parser->recursiveTagParse( $text )) veya $frame false olarak ayarlanırsa, daha sonra şablon parametreleri genişletilmeyecektir; {{{1}}} değiştirilmeyecek. Bu istenen davranış olmamasına rağmen, MW 1.16'dan önce mevcut olan tek seçenek buydu.

Bununla birlikte, recursiveTagParse kullanılırken bile etiketler için hâlâ atlanan bir ayrıştırma adımı Parser::preSaveTransform değeridir. preSaveTransform, kaydedilmek üzere olan vikimetinde kalıcı değişiklikler yapmaktan sorumlu olan, ayrıştırmanın ilk adımıdır, örneğin:

  • İmza dönüştürme (~~~, ~~~~, ~~~~~)
  • Boru hilesi olarak da bilinen bağlantı etiketlerini genişletme (örneğin, [[Help:Contents|]] ile [[Help:Contents|Contents]] olarak değiştirmek). Bu adım olmadan, [[Help:Contents|]] gibi stenografi bağlantılar geçersiz kabul edilir ve ayrıştırıldığında vikimetin biçiminde bırakılır.
  • {{subst:}} şablonlarını genişletme.

Orijinal preSaveTransform çağrısı, tüm uzantı etiketlerinde bu tür dönüşümleri kasıtlı olarak atlar. Kayıt öncesi dönüşümün yapılması gerekiyorsa, bunun yerine bir ayrıştırıcı işlevi kullanmayı düşünmelisiniz. Tüm etiket uzantıları, önceden kaydetme dönüşümü uygulanmış olan {{#tag:tagname|input|attribute_name=value}} kullanılarak bir ayrıştırıcı işlevi olarak da çağrılabilir.

Uzantı etiketime XML stili parametreleri nasıl iletebilirim?

Sürüm 1.5'ten beri

MediaWiki 1.5'ten beri, XML tarzı parametreler (etiket öznitelikleri) desteklenmektedir. Parametreler, bir ilişkisel dizi olarak, kanca işlevine ikinci parametre olarak iletilir. Değer dizelerinin zaten sizin için kodu çözülmüş HTML karakter ögelerine sahipler, bu nedenle onları HTML'ye geri gönderirseniz, HTML ekleme riskinden kaçınmak için htmlspecialchars( $codeToEncode, ENT_QUOTES ) kullanmayı unutmayın.

Uzantımın HTML çıkışının değiştirilmesini nasıl önleyebilirim?

Bir etiket uzantısının return değeri, neredeyse ayrıştırılmış metin olarak kabul edilir; bu, onun saf HTML olarak ele alınmadığı, ancak yine de biraz değiştirildiği anlamına gelir. Bir etiket uzantısının çıkışına yapılan iki ana şey vardır (Birkaç küçük şeyle birlikte):

  • Şerit işaretleyicileri değiştirin. Şerit işaretleyiciler, kaldırılan içeriği daha sonra yeniden eklemek için bir işaret olarak hareket etmek üzere vikimetni işlemenin çeşitli aşamalarında eklenen belirli ögelerdir. Bu, uzantıların genellikle endişelenmesi gereken bir şey değildir.
  • Parser::doBlockLevels, * ögelerin listelere ve baştaki boşlukla başlayan herhangi bir satırı diğer şeylerin yanı sıra Parser::doBlockLevels ile dönüştürür. Bu bazen bazı uzantılarda sorun olabilir.

Etiket uzantıları, return değerinin nasıl yorumlanacağını değiştirmek için yalnızca bir dize yerine bir dizi döndürmeyi de destekler (ayrıştırıcı işlevlere çok benzer). Dizinin 0. değeri HTML olmalıdır. Daha fazla ayrıştırmayı durdurmak için "markerType" anahtarı nowiki olarak ayarlanabilir. return [ $html, 'markerType' => 'nowiki' ]; gibi bir şey yapmak, $html değerinin daha fazla değiştirilmemesini ve sadece düz html olarak değerlendirilmemesini sağlar.

Uzantımın Special:Version sayfasında görünmesini nasıl sağlayabilirim?

Uzantınızın MediaWiki Special:Version sayfasında görüntülenmesi için PHP kodu içinde uzantı katkıları atamanız gerekir.

Bunu yapmak için, kanca satırından veya işlev tanımından önce ilk yürütülebilir kod satırı olarak bir $wgExtensionCredits değişkeni ekleyin.

Örnek bir uzantı katkısı şudur:

<?php
/**
 * ExampleExtension - this extension is an example that does nothing
 *
 * To activate this extension, add the following into your LocalSettings.php file:
 * require_once('$IP/extensions/Example.php');
 *
 * @ingroup Extensions
 * @author John Doe <john.doe@example.com>
 * @version 1.0
 * @link https://www.mediawiki.org/wiki/Extension:MyExtension Documentation
 * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License 2.0 or later
 */

/**
 * Protect against register_globals vulnerabilities.
 * This line must be present before any global variable is referenced.
 */
if( !defined( 'MEDIAWIKI' ) ) {
	echo( "This is an extension to the MediaWiki package and cannot be run standalone.\n" );
	die( -1 );
}

// Extension credits that will show up on Special:Version    
$wgExtensionCredits['validextensionclass'][] = array(
	'path'           => __FILE__,
	'name'           => 'Example',
	'version'        => '1.0',
	'author'         => 'John Doe', 
	'url'            => 'https://www.mediawiki.org/wiki/Extension:MyExtension',
	'descriptionmsg' => 'example-desc', // Message key in i18n file.
	'description'    => 'This extension is an example and performs no discernible function'
);

$wgExtensionMessagesFiles[] = __DIR__ . '/Example.i18n.php';

// Here is where we set up our extension
function wfExample(){
	// ...
}

validextensionclass ögesini aşağıdakilerden biriyle değiştirin (uzantınız birden fazla sınıfa dahil değilse. Sonra her sınıf için bir katkı oluşturun):

  • 'specialpage' — MediaWiki Özel Sayfalarına yapılan eklemeler için ayrılmıştır;
  • 'parserhook' — uzantınız MediaWiki'deki ayrıştırıcı işlevlerini değiştirir, tamamlar veya değiştirirse kullanılır;
  • 'variable' — MediaWiki'ye birden çok işlev ekleyen uzantı;
  • 'media' — uzantınız bir tür medya işleyicisiyse kullanılır
  • 'other' — diğer tüm uzantılar.

myextensionmsg, uzantınızın i18n.php dosyasında tanımlanması gerekecek olan uzantınızı açıklayan bir arabirim/i18n mesajının adıdır. Bu alanı atlarsanız, bunun yerine description alanı kullanılacaktır.

Geri çağrının içindeki etiket adını alma

Aynı geri çağırmayı paylaşan birkaç ‎<foo> ve ‎<bar> etiketiniz olduğunu ve geri arama işlevinin içinde, geri aramayı başlatan etiketin adını almak istediğinizi varsayalım.

$wgHooks['ParserFirstCallInit'][] = 'onParserFirstCallInit';

# ...

public function onParserFirstCallInit( Parser $parser ) {
	$parser->setHook( 'foo', 'sharedFunctionality' );
	$parser->setHook( 'bar', 'sharedFunctionality' );
}

# ...

public function sharedFunctionality( $input, array $args, Parser $parser, PPFrame $frame ) {
	// 'foo' ve 'bar' çağrıları nasıl ayırt edilir?
}

Kısa cevap şudur: etiket adı (foo veya bar) geri çağrının bağımsız değişkenlerinin hiçbirinde mevcut değildir. Ancak, her etiket için dinamik olarak ayrı bir geri çağrı oluşturarak bu sorunu çözebilirsiniz:

$wgHooks['ParserFirstCallInit'][] = 'onParserFirstCallInit';

# ...

public function onParserFirstCallInit( Parser $parser ) {
	// Her etiket adı için
	foreach ( [ 'foo', 'bar' ] as $tagName ) {
		// Dinamik olarak bir geri çağrı işlevi oluşturun
		$callback = function( $input, $args, $parser, $frame ) use ( $tagName ) {
			// Geri çağrı, paylaşılan işlevi çağırır.
			// Şimdi etiket adını parametre olarak ilettiğimize dikkat edin.
			return sharedFunctionality( $input, $args, $parser, $frame, $tagName );
		};
		// Geri çağrıyı etikete atayın
		$parser->setHook( $tagName, $callback );
	}
}

# ...

public function sharedFunctionality( $input, array $args, Parser $parser, PPFrame $frame, $tagName) {
	// Artık etiket adını alabilir ve o etiket için özel eylemler gerçekleştirebiliriz.
	switch ( $tagName ) {
		//...
	}
}

Toolbar buttons

Extension:WikiEditor provides an editing toolbar, allowing users to add tags into their editor by simply clicking a button. If you want a toolbar button for your new tag, create a file named something like toolbar-button.js in your extension's resources folder. The file should look like this:

var customizeToolbar = function () {
    $('#wpTextbox1').wikiEditor('addToToolbar', {
        section: 'main',
        group: 'format',
        tools: {
            "ExtensionName": { // uzantınızın adıyla değiştirin
                label: 'TagName', // düğmeyi gezdirirken görünmesi gereken etiketle değiştirin
                type: 'button',
                icon: "extensions/ExtensionName/images/button-image.svg", // düğmeye gitmesi gereken resmin yolu
                action: {
                    type: 'encapsulate',
                    options: {
                        pre: "<tagName>", // düğmeye tıklandığında eklenen etiketler
                        post: "</tagName>"
                    }
                }
            }
        }
    });
};

/* Görünümün düzenleme modunda olup olmadığını ve gerekli modüllerin mevcut olup olmadığını kontrol edin. Ardından, araç çubuğunu özelleştirin… */
if ( [ 'edit', 'submit' ].indexOf( mw.config.get( 'wgAction' ) ) !== -1 ) {
    mw.loader.using( 'user.options' ).then( function () {
        // Kullanıcı tercihi devre dışı bıraktıysa ([[phab:T54542#555387]]), bu "0" dizesi olabilir.
        if ( mw.user.options.get( 'usebetatoolbar' ) == 1 ) {
            $.when(
                mw.loader.using( 'ext.wikiEditor' ), $.ready
            ).then( customizeToolbar );
        }
    } );
}

Further details about customizing this file can be found here. Once you've created the file, you need to register it with ResourceLoader so it will be delivered to visitors; this is done by editing your extension.json:

"Hooks": {
    "BeforePageDisplay": "ExtensionName::onBeforePageDisplay"
}
"ResourceModules": {
    "ext.ExtensionName": {
        "scripts": ["toolbarButton.js"]
    }
}

Then, in your PHP file:

public static function onBeforePageDisplay( OutputPage $out ) {
    $out->addModules( [ 'ext.ExtensionName' ] );
}

Ayrıca bakınız