Merge "Goodbye Gadget/Gadget_definition namespaces!"

This commit is contained in:
jenkins-bot 2024-02-24 16:50:56 +00:00 committed by Gerrit Code Review
commit 88e934c6cb
17 changed files with 147 additions and 620 deletions

View file

@ -1,442 +0,0 @@
<?php
$namespaceNames = [];
// For wikis without Gadgets installed.
if ( !defined( 'NS_GADGET' ) ) {
define( 'NS_GADGET', 2300 );
define( 'NS_GADGET_TALK', 2301 );
define( 'NS_GADGET_DEFINITION', 2302 );
define( 'NS_GADGET_DEFINITION_TALK', 2303 );
}
$namespaceNames['alt'] = [
NS_GADGET => 'Гаджет',
NS_GADGET_TALK => аджетти_шӱӱжери',
NS_GADGET_DEFINITION => аджетти_аайлары',
NS_GADGET_DEFINITION_TALK => аджеттиҥ_аайларын_шӱӱжери',
];
$namespaceNames['an'] = [
NS_GADGET => 'Accesorio',
NS_GADGET_TALK => 'Descusión_accesorio',
NS_GADGET_DEFINITION => 'Accesorio_definición',
NS_GADGET_DEFINITION_TALK => 'Descusión_definición_accesorio',
];
$namespaceNames['anp'] = [
NS_GADGET => 'गैजेट',
NS_GADGET_TALK => 'गैजेट_वार्ता',
NS_GADGET_DEFINITION => 'गैजेट_परिभाषा',
NS_GADGET_DEFINITION_TALK => 'गैजेट_परिभाषा_वार्ता',
];
$namespaceNames['ar'] = [
NS_GADGET => 'إضافة',
NS_GADGET_TALK => 'نقاش_الإضافة',
NS_GADGET_DEFINITION => 'تعريف_الإضافة',
NS_GADGET_DEFINITION_TALK => 'نقاش_تعريف_الإضافة',
];
$namespaceNames['ast'] = [
NS_GADGET => 'Accesoriu',
NS_GADGET_TALK => 'Accesoriu_alderique',
NS_GADGET_DEFINITION => 'Accesoriu_definición',
NS_GADGET_DEFINITION_TALK => 'Accesoriu_definición_alderique',
];
$namespaceNames['atj'] = [
NS_GADGET => 'Gadget',
NS_GADGET_TALK => 'Ka_ici_aimihitonaniwok_gadget',
NS_GADGET_DEFINITION => 'Tipatcitcikan_e_icinakok_gadget',
NS_GADGET_DEFINITION_TALK => 'Ka_ici_aimihitonaniwok_tipatcitcikan_gadget_otci',
];
$namespaceNames['av'] = [
NS_GADGET => 'Гаджет',
NS_GADGET_TALK => аджеталъул_бахӀс',
NS_GADGET_DEFINITION => аджеталъул_баян_чӀезаби',
NS_GADGET_DEFINITION_TALK => аджеталъул_баян_чӀезабиялъул_бахӀс',
];
$namespaceNames['az'] = [
NS_GADGET => 'Qadcet',
NS_GADGET_TALK => 'Qadcet müzakirəsi',
];
$namespaceNames['azb'] = [
NS_GADGET => 'آلت',
NS_GADGET_TALK => 'آلت_دانیشیغی',
NS_GADGET_DEFINITION => 'آلت_آچیقلاماسی',
NS_GADGET_DEFINITION_TALK => 'آلت_آچیقلاماسی_دانیشیغی',
];
$namespaceNames['ba'] = [
NS_GADGET => 'Гаджет',
NS_GADGET_TALK => аджет_буйынсаекерләшеү',
NS_GADGET_DEFINITION => аджет_билдәһе',
NS_GADGET_DEFINITION_TALK => аджет_билдәһе_буйынсаекерләшеү',
];
$namespaceNames['bgn'] = [
NS_GADGET => 'وسیلهان',
NS_GADGET_TALK => 'وسیلهان_ئی_گپ',
NS_GADGET_DEFINITION => 'وسیلهانی_شرح',
NS_GADGET_DEFINITION_TALK => 'وسیلهانی_شرح_ئی_گپ',
];
$namespaceNames['bn'] = [
NS_GADGET => 'গ্যাজেট',
NS_GADGET_TALK => 'গ্যাজেট_আলোচনা',
NS_GADGET_DEFINITION => 'গ্যাজেট_সংজ্ঞা',
NS_GADGET_DEFINITION_TALK => 'গ্যাজেট_সংজ্ঞার_আলোচনা',
];
$namespaceNames['ce'] = [
NS_GADGET => 'Гаджет',
NS_GADGET_TALK => аджет_йийцар',
NS_GADGET_DEFINITION => аджет_къастор',
NS_GADGET_DEFINITION_TALK => аджет_къастор_дийцар',
];
$namespaceNames['ckb'] = [
NS_GADGET => 'ئامراز',
NS_GADGET_TALK => 'وتووێژی_ئامراز',
NS_GADGET_DEFINITION => 'پێناسهی_ئامراز',
NS_GADGET_DEFINITION_TALK => 'وتووێژی_پێناسهی_ئامراز',
];
$namespaceNames['cs'] = [
NS_GADGET => 'Udělátko',
NS_GADGET_TALK => 'Diskuse_k_udělátku',
NS_GADGET_DEFINITION => 'Definice_udělátka',
NS_GADGET_DEFINITION_TALK => 'Diskuse_k_definici_udělátka',
];
$namespaceNames['de'] = [
NS_GADGET => 'Gadget',
NS_GADGET_TALK => 'Gadget_Diskussion',
NS_GADGET_DEFINITION => 'Gadget-Definition',
NS_GADGET_DEFINITION_TALK => 'Gadget-Definition_Diskussion',
];
$namespaceNames['din'] = [
NS_GADGET => 'Muluuitet',
NS_GADGET_TALK => 'Jam_wɛ̈t_ë_muluuitet',
NS_GADGET_DEFINITION => 'Wɛ̈tdic_ë_muluuitet',
NS_GADGET_DEFINITION_TALK => 'Jam_wɛ̈t_ë_wɛ̈tdic_ë_muluuitet',
];
$namespaceNames['diq'] = [
NS_GADGET => 'Halet',
NS_GADGET_TALK => 'Halet_vaten',
NS_GADGET_DEFINITION => 'Halet_şınasnayış',
NS_GADGET_DEFINITION_TALK => 'Halet_şınasnayış_vaten',
];
$namespaceNames['dty'] = [
NS_GADGET => 'ग्याजेट',
NS_GADGET_TALK => 'ग्याजेट_कुरणि',
NS_GADGET_DEFINITION => 'ग्याजेट_परिभाषा',
NS_GADGET_DEFINITION_TALK => 'ग्याजेट_परिभाषा_कुरणि',
];
$namespaceNames['en'] = [
NS_GADGET => 'Gadget',
NS_GADGET_TALK => 'Gadget_talk',
NS_GADGET_DEFINITION => 'Gadget_definition',
NS_GADGET_DEFINITION_TALK => 'Gadget_definition_talk',
];
$namespaceNames['es'] = [
NS_GADGET => 'Accesorio',
NS_GADGET_TALK => 'Accesorio_discusión',
NS_GADGET_DEFINITION => 'Accesorio_definición',
NS_GADGET_DEFINITION_TALK => 'Accesorio_definición_discusión',
];
$namespaceNames['et'] = [
NS_GADGET => 'Tööriist',
NS_GADGET_TALK => 'Tööriista_arutelu',
NS_GADGET_DEFINITION => 'Tööriista_määratlus',
NS_GADGET_DEFINITION_TALK => 'Tööriista_määratluse_arutelu',
];
$namespaceNames['eu'] = [
NS_GADGET => 'Gadget',
NS_GADGET_TALK => 'Gadget_eztabaida',
NS_GADGET_DEFINITION => 'Gadget_definizio',
NS_GADGET_DEFINITION_TALK => 'Gadget_definizio_eztabaida',
];
$namespaceNames['fa'] = [
NS_GADGET => 'ابزار',
NS_GADGET_TALK => 'بحث_ابزار',
NS_GADGET_DEFINITION => 'توضیحات_ابزار',
NS_GADGET_DEFINITION_TALK => 'بحث_توضیحات_ابزار',
];
$namespaceNames['fi'] = [
NS_GADGET => 'Pienoisohjelma',
NS_GADGET_TALK => 'Keskustelu_pienoisohjelmasta',
NS_GADGET_DEFINITION => 'Pienoisohjelman_määritys',
NS_GADGET_DEFINITION_TALK => 'Keskustelu_pienoisohjelman_määrityksestä',
];
$namespaceNames['fr'] = [
NS_GADGET => 'Gadget',
NS_GADGET_TALK => 'Discussion_gadget',
NS_GADGET_DEFINITION => 'Définition_de_gadget',
NS_GADGET_DEFINITION_TALK => 'Discussion_définition_de_gadget',
];
$namespaceNames['he'] = [
NS_GADGET => 'גאדג\'ט',
NS_GADGET_TALK => יחת_גאדג\'ט',
NS_GADGET_DEFINITION => 'הגדרת_גאדג\'ט',
NS_GADGET_DEFINITION_TALK => יחת_הגדרת_גאדג\'ט',
];
$namespaceNames['hi'] = [
NS_GADGET => 'गैजेट',
NS_GADGET_TALK => 'गैजेट वार्ता',
NS_GADGET_DEFINITION => 'गैजेट परिभाषा',
NS_GADGET_DEFINITION_TALK => 'गैजेट परिभाषा वार्ता',
];
$namespaceNames['inh'] = [
NS_GADGET => 'Гаджет',
NS_GADGET_TALK => аджет_ювцар',
NS_GADGET_DEFINITION => аджета_къоастадар',
NS_GADGET_DEFINITION_TALK => аджета_къоастадарувцар',
];
$namespaceNames['is'] = [
NS_GADGET => 'Smától',
NS_GADGET_TALK => 'Smátólaspjall',
NS_GADGET_DEFINITION => 'Smátóla_skilgreining',
NS_GADGET_DEFINITION_TALK => 'Smátóla_skilgreiningarspjall',
];
$namespaceNames['it'] = [
NS_GADGET => 'Accessorio',
NS_GADGET_TALK => 'Discussioni_accessorio',
NS_GADGET_DEFINITION => 'Definizione_accessorio',
NS_GADGET_DEFINITION_TALK => 'Discussioni_definizione_accessorio',
];
$namespaceNames['ko'] = [
NS_GADGET => '소도구',
NS_GADGET_TALK => '소도구토론',
NS_GADGET_DEFINITION => '소도구정의',
NS_GADGET_DEFINITION_TALK => '소도구정의토론',
];
$namespaceNames['ks-arab'] = [
NS_GADGET => 'آلہٕ',
NS_GADGET_TALK => 'آلہٕ_کَتھ',
NS_GADGET_DEFINITION => 'آلہٕ_تَعارُف',
NS_GADGET_DEFINITION_TALK => 'آلہٕ_تَعارُف_کَتھ',
];
$namespaceNames['ky'] = [
NS_GADGET => 'Гаджет',
NS_GADGET_TALK => аджетти_талкуулоо',
NS_GADGET_DEFINITION => аджеттин_түшүндүрмөсү',
NS_GADGET_DEFINITION_TALK => аджеттин_түшүндүрмөсүн_талкуулоо',
];
$namespaceNames['lfn'] = [
NS_GADGET => 'Macineta',
NS_GADGET_TALK => 'Macineta_Discute',
NS_GADGET_DEFINITION => 'Defini_de_macineta',
NS_GADGET_DEFINITION_TALK => 'Defini_de_macineta_Discute',
];
$namespaceNames['lrc'] = [
NS_GADGET => 'گأجئت',
NS_GADGET_TALK => 'چأک_چئنە_گأجئت',
NS_GADGET_DEFINITION => 'توضییا_گأجئت',
NS_GADGET_DEFINITION_TALK => 'چأک_چئنە_توضییا_گأجئت',
];
$namespaceNames['ms'] = [
NS_GADGET => 'Alat',
NS_GADGET_TALK => 'Perbincangan_alat',
NS_GADGET_DEFINITION => 'Penerangan_alat',
NS_GADGET_DEFINITION_TALK => 'Perbincangan_penerangan_alat',
];
$namespaceNames['ms-arab'] = [
NS_GADGET => 'الت',
NS_GADGET_TALK => 'ڤربينچڠن_الت',
NS_GADGET_DEFINITION => 'ڤنرڠن_الت',
NS_GADGET_DEFINITION_TALK => 'ڤربينچڠن_ڤنرڠن_الت',
];
$namespaceNames['mnw'] = [
NS_GADGET => 'ကိရိယာ',
NS_GADGET_TALK => 'ကိရိယာ_ဓရီုကျာ',
NS_GADGET_DEFINITION => 'ကိရိယာ_ပွံက်အဓိပ္ပါယ်',
NS_GADGET_DEFINITION_TALK => 'ကိရိယာ_ပွံက်အဓိပ္ပါယ်_ဓရီုကျာ',
];
$namespaceNames['mwl'] = [
NS_GADGET => 'Gadget',
NS_GADGET_TALK => 'Cumbersa_gadget',
NS_GADGET_DEFINITION => 'Defeniçon_gadget',
NS_GADGET_DEFINITION_TALK => 'Cumbersa_defeniçon_gadget',
];
$namespaceNames['mzn'] = [
NS_GADGET => 'گجت',
NS_GADGET_TALK => 'گجت_گپ',
NS_GADGET_DEFINITION => 'گجت_توضیحات',
NS_GADGET_DEFINITION_TALK => 'گجت_توضیحات_گپ',
];
$namespaceNames['my'] = [
NS_GADGET => 'ကိရိယာငယ်',
NS_GADGET_TALK => 'ကိရိယာငယ်_ဆွေးနွေးချက်',
NS_GADGET_DEFINITION => 'ကိရိယာငယ်_အဓိပ္ပာယ်',
NS_GADGET_DEFINITION_TALK => 'ကိရိယာငယ်_အဓိပ္ပာယ်_ဆွေးနွေးချက်',
];
$namespaceNames['nap'] = [
NS_GADGET => 'Pazziella',
NS_GADGET_TALK => 'Pazziella_chiàcchiera',
NS_GADGET_DEFINITION => 'Pazziella_definizzione',
NS_GADGET_DEFINITION_TALK => 'Pazziella_definizzione_chiàcchiera',
];
$namespaceNames['nl'] = [
NS_GADGET => 'Uitbreiding',
NS_GADGET_TALK => 'Overleg_uitbreiding',
NS_GADGET_DEFINITION => 'Uitbreidingsdefinitie',
NS_GADGET_DEFINITION_TALK => 'Overleg_uitbreidingsdefinitie',
];
$namespaceNames['or'] = [
NS_GADGET => 'ଗ୍ୟାଜେଟ',
NS_GADGET_TALK => 'ଗ୍ୟାଜେଟ_ଆଲୋଚନା',
NS_GADGET_DEFINITION => 'ଗ୍ୟାଜେଟ_ସଂଜ୍ଞା',
NS_GADGET_DEFINITION_TALK => 'ଗ୍ୟାଜେଟ_ସଂଜ୍ଞା_ଆଲୋଚନା',
];
$namespaceNames['pa'] = [
NS_GADGET => 'ਗੈਜਟ',
NS_GADGET_TALK => 'ਗੈਜਟ_ਗੱਲ-ਬਾਤ',
NS_GADGET_DEFINITION => 'ਗੈਜਟ_ਪਰਿਭਾਸ਼ਾ',
NS_GADGET_DEFINITION_TALK => 'ਗੈਜਟ_ਪਰਿਭਾਸ਼ਾ_ਗੱਲ-ਬਾਤ',
];
$namespaceNames['pcm'] = [
NS_GADGET => 'Gajet',
NS_GADGET_TALK => 'Gajet_tok_abaut_am',
NS_GADGET_DEFINITION => 'Gajet_definishon',
NS_GADGET_DEFINITION_TALK => 'Gajet_definishon_tok_abaut_am',
];
$namespaceNames['pl'] = [
NS_GADGET => 'Gadżet',
NS_GADGET_TALK => 'Dyskusja_gadżetu',
NS_GADGET_DEFINITION => 'Definicja_gadżetu',
NS_GADGET_DEFINITION_TALK => 'Dyskusja_definicji_gadżetu',
];
$namespaceNames['pnb'] = [
NS_GADGET => 'آلہ',
NS_GADGET_TALK => 'آلہ_گل_بات',
NS_GADGET_DEFINITION => 'آلہ_تعریف',
NS_GADGET_DEFINITION_TALK => 'آلہ_تعریف_گل_بات',
];
$namespaceNames['ro'] = [
NS_GADGET => 'Gadget',
NS_GADGET_TALK => 'Discuție_Gadget',
NS_GADGET_DEFINITION => 'Definiție_gadget',
NS_GADGET_DEFINITION_TALK => 'Discuție_Definiție_gadget',
];
$namespaceNames['ru'] = [
NS_GADGET => 'Гаджет',
NS_GADGET_TALK => 'Обсуждение_гаджета',
NS_GADGET_DEFINITION => 'Определение_гаджета',
NS_GADGET_DEFINITION_TALK => 'Обсуждение_определения_гаджета',
];
$namespaceNames['sat'] = [
NS_GADGET => 'ᱥᱟᱢᱟᱱᱚᱢ',
NS_GADGET_TALK => 'ᱥᱟᱢᱟᱱᱚᱢ_ᱜᱟᱞᱢᱟᱨᱟᱣ',
NS_GADGET_DEFINITION => 'ᱥᱟᱢᱟᱱᱚᱢ_ᱢᱮᱱᱮᱛᱮᱫ',
NS_GADGET_DEFINITION_TALK => 'ᱥᱟᱢᱟᱱᱚᱢ_ᱢᱮᱱᱮᱛᱮᱫ_ᱜᱟᱞᱢᱟᱨᱟᱣ',
];
$namespaceNames['scn'] = [
NS_GADGET => 'Accissoriu',
NS_GADGET_TALK => 'Discussioni_accissoriu',
NS_GADGET_DEFINITION => 'Difinizzioni_accissoriu',
NS_GADGET_DEFINITION_TALK => 'Discussioni_difinizzioni_accissoriu',
];
$namespaceNames['sd'] = [
NS_GADGET => 'گيجيٽ',
NS_GADGET_TALK => 'گيجيٽ_بحث',
NS_GADGET_DEFINITION => 'گيجيٽ_وصف',
NS_GADGET_DEFINITION_TALK => 'گيجيٽ_وصف_بحث',
];
$namespaceNames['shn'] = [
NS_GADGET => 'ၶိူင်ႈပိတ်းပွတ်း',
NS_GADGET_TALK => 'ဢုပ်ႇၵုမ်_ၶိူင်ႈပိတ်းပွတ်း',
NS_GADGET_DEFINITION => 'ပိုတ်ႇတီႈပွင်ႇ_ၶိူင်ႈပိတ်းပွတ်း',
NS_GADGET_DEFINITION_TALK => 'ဢုပ်ႇၵုမ်_ပိုတ်ႇတီႈပွင်ႇ_ၶိူင်ႈပိတ်းပွတ်း',
];
$namespaceNames['sl'] = [
NS_GADGET => 'Pripomoček',
NS_GADGET_TALK => 'Pogovor_o_pripomočku',
NS_GADGET_DEFINITION => 'Opredelitev_pripomočka',
NS_GADGET_DEFINITION_TALK => 'Pogovor_o_opredelitvi_pripomočka',
];
$namespaceNames['sr-ec'] = [
NS_GADGET => 'Справица',
NS_GADGET_TALK => 'Разговор_о_справици',
NS_GADGET_DEFINITION => ефиниција_справице',
NS_GADGET_DEFINITION_TALK => 'Разговор_оефиницији_справице',
];
$namespaceNames['sr-el'] = [
NS_GADGET => 'Spravica',
NS_GADGET_TALK => 'Razgovor_o_spravici',
NS_GADGET_DEFINITION => 'Definicija_spravice',
NS_GADGET_DEFINITION_TALK => 'Razgovor_o_definiciji_spravice',
];
$namespaceNames['ti'] = [
NS_GADGET => 'መሳርሒ',
NS_GADGET_TALK => 'ምይይጥ_መሳርሒ',
NS_GADGET_DEFINITION => 'መብርሂ_መሳርሒ',
NS_GADGET_DEFINITION_TALK => 'ምይይጥ_መብርሂ_መሳርሒ',
];
$namespaceNames['ur'] = [
NS_GADGET => 'آلہ',
NS_GADGET_TALK => 'تبادلۂ_خیال_آلہ',
NS_GADGET_DEFINITION => 'تعریف_آلہ',
NS_GADGET_DEFINITION_TALK => 'تبادلۂ_خیال_تعریف_آلہ',
];
$namespaceNames['uz'] = [
NS_GADGET => 'Gadjet',
NS_GADGET_TALK => 'Gadjet_munozarasi',
NS_GADGET_DEFINITION => 'Gadjet_taʼrifi',
NS_GADGET_DEFINITION_TALK => 'Gadjet_taʼrifi_munozarasi',
];
$namespaceNames['vi'] = [
NS_GADGET => 'Tiện_ích',
NS_GADGET_TALK => 'Thảo_luận_Tiện_ích',
NS_GADGET_DEFINITION => 'Định_nghĩa_tiện_ích',
NS_GADGET_DEFINITION_TALK => 'Thảo_luận_Định_nghĩa_tiện_ích',
];

View file

@ -11,38 +11,9 @@
"MediaWiki": ">= 1.42"
},
"type": "other",
"namespaces": [
{
"id": 2300,
"constant": "NS_GADGET",
"name": "Gadget",
"capitallinkoverride": false
},
{
"id": 2301,
"constant": "NS_GADGET_TALK",
"name": "Gadget_talk"
},
{
"id": 2302,
"constant": "NS_GADGET_DEFINITION",
"name": "Gadget_definition",
"protection": "gadgets-definition-edit",
"capitallinkoverride": false,
"defaultcontentmodel": "GadgetDefinition"
},
{
"id": 2303,
"constant": "NS_GADGET_DEFINITION_TALK",
"name": "Gadget_definition_talk"
}
],
"ContentHandlers": {
"GadgetDefinition": "MediaWiki\\Extension\\Gadgets\\Content\\GadgetDefinitionContentHandler"
},
"AvailableRights": [
"gadgets-definition-edit"
],
"SpecialPages": {
"Gadgets": {
"class": "MediaWiki\\Extension\\Gadgets\\Special\\SpecialGadgets",
@ -78,8 +49,7 @@
]
},
"ExtensionMessagesFiles": {
"GadgetsAlias": "Gadgets.alias.php",
"GadgetsNamespaces": "Gadgets.namespaces.php"
"GadgetsAlias": "Gadgets.alias.php"
},
"RawHtmlMessages": [
"gadgets-definition"

View file

@ -59,9 +59,5 @@
"gadgets-validate-invalidtitle": "Page title \"$1\" is invalid",
"gadgets-validate-unknownpages": "Contains one or more pages without .js, .css or .json suffix. They would not be used.",
"gadgets-validate-nopage": "Page \"$1\" does not exist.",
"right-gadgets-definition-edit": "Edit gadget definitions",
"action-gadgets-definition-edit": "edit this gadget definition",
"gadgets-wrong-contentmodel": "Pages in {{ns:2302}} namespace must be of GadgetDefinition content model.",
"gadgets-supports-urlload": "This gadget supports loading via URL with <code>?withgadget</code> query parameter.",
"gadgets-protected": "You do not have permission to edit pages in {{ns:2300}} namespace."
"gadgets-supports-urlload": "This gadget supports loading via URL with <code>?withgadget</code> query parameter."
}

View file

@ -74,9 +74,5 @@
"gadgets-validate-invalidtitle": "Warning message to indicate that the page title is invalid. Parameters:\n* $1 - page name",
"gadgets-validate-unknownpages": "Warning message to indicate that a gadget contains pages without .js, .css or .json suffix, which are not recognised.",
"gadgets-validate-nopage": "Warning message to indicate the script/style/json page does not exist. Parameters:\n* $1 - page name",
"right-gadgets-definition-edit": "{{doc-right|gadgets-definition-edit}}",
"action-gadgets-definition-edit": "{{doc-action|gadgets-definition-edit}}",
"gadgets-wrong-contentmodel": "Error message shown while trying to change the content model of a page in gadget definition namespace to other than GadgetDefinition.",
"gadgets-supports-urlload": "Used in [[Special:Gadgets]], if the gadget supports ?withgadget query parameter.",
"gadgets-protected": "Error message shown while trying to edit any non-CSS/JS/JSON pages in gadget namespace, if user doesn't have permission"
"gadgets-supports-urlload": "Used in [[Special:Gadgets]], if the gadget supports ?withgadget query parameter."
}

View file

@ -12,8 +12,12 @@ use MediaWiki\Title\Title;
class CodeEditorHooks implements CodeEditorGetPageLanguageHook {
/**
* Set the CodeEditor language for Gadget definition pages. It already
* knows the language for Gadget: namespace pages.
* Set the CodeEditor language for GadgetDefinition pages.
*
* The CodeEditor extension sets the default syntax highlight language based
* on the content model (not page title), so while gadget definitions have ".json"
* page titles, the fact that we use a more specific subclass as content model,
* means we must explicitly opt-in to JSON syntax highlighting.
*
* @param Title $title
* @param string|null &$lang

View file

@ -24,7 +24,9 @@ use Content;
use FormatJson;
use JsonContentHandler;
use MediaWiki\Content\Renderer\ContentParseParams;
use MediaWiki\Extension\Gadgets\MediaWikiGadgetsJsonRepo;
use MediaWiki\Linker\Linker;
use MediaWiki\MediaWikiServices;
use MediaWiki\Parser\ParserOutput;
use MediaWiki\Title\Title;
@ -38,7 +40,7 @@ class GadgetDefinitionContentHandler extends JsonContentHandler {
* @return bool
*/
public function canBeUsedOn( Title $title ) {
return $title->inNamespace( NS_GADGET_DEFINITION );
return MediaWikiGadgetsJsonRepo::isGadgetDefinitionTitle( $title );
}
/** @inheritDoc */
@ -102,23 +104,28 @@ class GadgetDefinitionContentHandler extends JsonContentHandler {
if ( $data !== null ) {
if ( isset( $data->module->pages ) ) {
foreach ( $data->module->pages as &$page ) {
$title = Title::makeTitleSafe( NS_GADGET, $page );
$title = Title::makeTitleSafe( NS_MEDIAWIKI, "Gadget-$page" );
$this->makeLink( $parserOutput, $page, $title );
}
}
$gadgetRepo = MediaWikiServices::getInstance()->getService( 'GadgetsRepo' );
if ( isset( $data->module->dependencies ) ) {
foreach ( $data->module->dependencies as &$dep ) {
if ( str_starts_with( $dep, 'ext.gadget.' ) ) {
$gadgetId = explode( 'ext.gadget.', $dep )[ 1 ];
$title = Title::makeTitleSafe( NS_GADGET_DEFINITION, $gadgetId );
$this->makeLink( $parserOutput, $dep, $title );
$title = $gadgetRepo->getGadgetDefinitionTitle( $gadgetId );
if ( $title ) {
$this->makeLink( $parserOutput, $dep, $title );
}
}
}
}
if ( isset( $data->module->peers ) ) {
foreach ( $data->module->peers as &$peer ) {
$title = Title::makeTitleSafe( NS_GADGET_DEFINITION, $peer );
$this->makeLink( $parserOutput, $peer, $title );
$title = $gadgetRepo->getGadgetDefinitionTitle( $peer );
if ( $title ) {
$this->makeLink( $parserOutput, $peer, $title );
}
}
}
if ( isset( $data->module->messages ) ) {

View file

@ -119,7 +119,7 @@ class Gadget {
*/
public static function serializeDefinition( string $id, array $data ): array {
$prefixGadgetNs = static function ( $page ) {
return 'Gadget:' . $page;
return GadgetRepo::RESOURCE_TITLE_PREFIX . $page;
};
return [
'category' => $data['settings']['category'],

View file

@ -15,10 +15,8 @@ abstract class GadgetRepo {
*/
private static $instance;
/**
* @var string
*/
protected $titlePrefix;
/** @internal */
public const RESOURCE_TITLE_PREFIX = 'MediaWiki:Gadget-';
/**
* Get the ids of the gadgets provided by this repository
@ -82,17 +80,17 @@ abstract class GadgetRepo {
}
/**
* Get the script file name without the "MediaWiki:Gadget-" or "Gadget:" prefix.
* This name is used by the client-side require() so that require("Data.json") resolves
* to either "MediaWiki:Gadget-Data.json" or "Gadget:Data.json" depending on the
* $wgGadgetsRepo configuration, enabling easy migration between the configuration modes.
* Get the page name without "MediaWiki:Gadget-" prefix.
*
* This name is used by `mw.loader.require()` so that `require("./example.json")` resolves
* to `MediaWiki:Gadget-example.json`.
*
* @param string $titleText
* @return string
*/
public function titleWithoutPrefix( string $titleText ): string {
$numReplaces = 1; // there will only one occurrence of the prefix
return str_replace( $this->titlePrefix, '', $titleText, $numReplaces );
return str_replace( self::RESOURCE_TITLE_PREFIX, '', $titleText, $numReplaces );
}
/**

View file

@ -362,40 +362,22 @@ class Hooks implements
$status->merge( $validateStatus );
return false;
}
} else {
$title = $context->getTitle();
if ( $title->inNamespace( NS_GADGET_DEFINITION ) ) {
$status->merge( Status::newFatal( "gadgets-wrong-contentmodel" ) );
return false;
}
}
return true;
}
/**
* Mark the Title as having a content model of javascript or css for pages
* in the Gadget namespace based on their file extension
* Create "MediaWiki:Gadgets/<id>.json" pages with GadgetDefinitionContent
*
* @param Title $title
* @param string &$model
* @return bool
*/
public function onContentHandlerDefaultModelFor( $title, &$model ) {
if ( $title->inNamespace( NS_GADGET ) ) {
preg_match( '!\.(css|js|json)$!u', $title->getText(), $ext );
$ext = $ext[1] ?? '';
switch ( $ext ) {
case 'js':
$model = 'javascript';
return false;
case 'css':
$model = 'css';
return false;
case 'json':
$model = 'json';
return false;
}
if ( MediaWikiGadgetsJsonRepo::isGadgetDefinitionTitle( $title ) ) {
$model = 'GadgetDefinition';
return false;
}
return true;
@ -430,36 +412,13 @@ class Hooks implements
* @return bool|void
*/
public function onGetUserPermissionsErrors( $title, $user, $action, &$result ) {
if ( $action !== 'edit' || !$title->inNamespace( NS_GADGET ) ) {
return true;
if ( $action === 'edit'
&& MediaWikiGadgetsJsonRepo::isGadgetDefinitionTitle( $title )
) {
if ( !$user->isAllowed( 'editsitejs' ) ) {
$result = ApiMessage::create( wfMessage( 'sitejsprotected' ), 'sitejsprotected' );
return false;
}
}
switch ( $title->getContentModel() ) {
case CONTENT_MODEL_JSON:
if ( !$user->isAllowed( 'editsitejson' ) ) {
$result = ApiMessage::create( wfMessage( 'sitejsonprotected' ), 'sitejsonprotected' );
return false;
}
break;
case CONTENT_MODEL_CSS:
if ( !$user->isAllowed( 'editsitecss' ) ) {
$result = ApiMessage::create( wfMessage( 'sitecssprotected' ), 'sitecssprotected' );
return false;
}
break;
case CONTENT_MODEL_JAVASCRIPT:
if ( !$user->isAllowed( 'editsitejs' ) ) {
$result = ApiMessage::create( wfMessage( 'sitejsprotected' ), 'sitejsprotected' );
return false;
}
break;
default:
// For any other pages in the namespace
if ( !$user->isAllowed( 'editsitejs' ) ) {
$result = ApiMessage::create( wfMessage( 'gadgets-protected' ), 'permissiondenied' );
return false;
}
break;
}
return true;
}
}

View file

@ -40,9 +40,6 @@ class MediaWikiGadgetsDefinitionRepo extends GadgetRepo {
/** @var array|null */
private $definitions;
/** @var string */
protected $titlePrefix = 'MediaWiki:Gadget-';
private WANObjectCache $wanCache;
private RevisionLookup $revLookup;
@ -300,7 +297,7 @@ class MediaWikiGadgetsDefinitionRepo extends GadgetRepo {
}
foreach ( preg_split( '/\s*\|\s*/', $pages, -1, PREG_SPLIT_NO_EMPTY ) as $page ) {
$info['pages'][] = $this->titlePrefix . trim( $page );
$info['pages'][] = self::RESOURCE_TITLE_PREFIX . trim( $page );
}
return new Gadget( $info );

View file

@ -10,23 +10,23 @@ use MediaWiki\Revision\SlotRecord;
use MediaWiki\Title\Title;
use WANObjectCache;
use Wikimedia\Rdbms\Database;
use Wikimedia\Rdbms\IExpression;
use Wikimedia\Rdbms\LikeValue;
/**
* GadgetRepo implementation where each gadget has a page in
* the Gadget definition namespace, and scripts and styles are
* located in the Gadget namespace.
* Gadgets repo powered by `MediaWiki:Gadgets/<id>.json` pages.
*
* Each gadget has its own gadget definition page, using GadgetDefinitionContent.
*/
class GadgetDefinitionNamespaceRepo extends GadgetRepo {
class MediaWikiGadgetsJsonRepo extends GadgetRepo {
/**
* How long in seconds the list of gadget ids and
* individual gadgets should be cached for (1 day)
*/
private const CACHE_TTL = 86400;
/**
* @var string
*/
protected $titlePrefix = 'Gadget:';
public const DEF_PREFIX = 'Gadgets/';
public const DEF_SUFFIX = '.json';
/**
* @var WANObjectCache
@ -52,7 +52,7 @@ class GadgetDefinitionNamespaceRepo extends GadgetRepo {
$key = $this->getGadgetIdsKey();
$fname = __METHOD__;
return $this->wanCache->getWithSetCallback(
$titles = $this->wanCache->getWithSetCallback(
$key,
self::CACHE_TTL,
static function ( $oldValue, &$ttl, array &$setOpts ) use ( $fname ) {
@ -62,25 +62,44 @@ class GadgetDefinitionNamespaceRepo extends GadgetRepo {
return $dbr->newSelectQueryBuilder()
->select( 'page_title' )
->from( 'page' )
->where( [ 'page_namespace' => NS_GADGET_DEFINITION ] )
->where( [
'page_namespace' => NS_MEDIAWIKI,
'page_content_model' => 'GadgetDefinition',
$dbr->expr(
'page_title',
IExpression::LIKE,
new LikeValue( self::DEF_PREFIX, $dbr->anyString(), self::DEF_SUFFIX )
)
] )
->caller( $fname )
->fetchFieldValues();
},
[
'checkKeys' => [ $key ],
'pcTTL' => WANObjectCache::TTL_PROC_SHORT,
// Bump when changing the database query.
'version' => 2,
'lockTSE' => 30
]
);
$ids = [];
foreach ( $titles as $title ) {
$id = self::getGadgetId( $title );
if ( $id !== '' ) {
$ids[] = $id;
}
}
return $ids;
}
/**
* @inheritDoc
*/
public function handlePageUpdate( LinkTarget $target ): void {
if ( $target->inNamespace( NS_GADGET_DEFINITION ) ) {
if ( $this->isGadgetDefinitionTitle( $target ) ) {
$this->purgeGadgetIdsList();
$this->purgeGadgetEntry( $target->getText() );
$this->purgeGadgetEntry( self::getGadgetId( $target->getText() ) );
}
}
@ -91,11 +110,39 @@ class GadgetDefinitionNamespaceRepo extends GadgetRepo {
$this->wanCache->touchCheckKey( $this->getGadgetIdsKey() );
}
/**
* @param string $title Gadget definition page title
* @return string Gadget ID
*/
private static function getGadgetId( string $title ): string {
if ( !str_starts_with( $title, self::DEF_PREFIX ) || !str_ends_with( $title, self::DEF_SUFFIX ) ) {
throw new InvalidArgumentException( 'Invalid definition page title' );
}
return substr( $title, strlen( self::DEF_PREFIX ), -strlen( self::DEF_SUFFIX ) );
}
/**
* @param LinkTarget $target
* @return bool
*/
public static function isGadgetDefinitionTitle( LinkTarget $target ): bool {
if ( !$target->inNamespace( NS_MEDIAWIKI ) ) {
return false;
}
$title = $target->getText();
try {
self::getGadgetId( $title );
return true;
} catch ( InvalidArgumentException $e ) {
return false;
}
}
/**
* @inheritDoc
*/
public function getGadgetDefinitionTitle( string $id ): ?Title {
return Title::makeTitleSafe( NS_GADGET_DEFINITION, $id );
return Title::makeTitleSafe( NS_MEDIAWIKI, self::DEF_PREFIX . $id . self::DEF_SUFFIX );
}
/**
@ -110,7 +157,7 @@ class GadgetDefinitionNamespaceRepo extends GadgetRepo {
self::CACHE_TTL,
function ( $old, &$ttl, array &$setOpts ) use ( $id ) {
$setOpts += Database::getCacheSetOptions( wfGetDB( DB_REPLICA ) );
$title = Title::makeTitleSafe( NS_GADGET_DEFINITION, $id );
$title = $this->getGadgetDefinitionTitle( $id );
if ( !$title ) {
$ttl = WANObjectCache::TTL_UNCACHEABLE;
return null;
@ -143,7 +190,7 @@ class GadgetDefinitionNamespaceRepo extends GadgetRepo {
);
if ( $gadget === null ) {
throw new InvalidArgumentException( "No gadget registered for '$id'" );
throw new InvalidArgumentException( "Unknown gadget $id" );
}
return new Gadget( $gadget );
@ -162,7 +209,7 @@ class GadgetDefinitionNamespaceRepo extends GadgetRepo {
* @return string
*/
private function getGadgetIdsKey() {
return $this->wanCache->makeKey( 'gadgets', 'namespace', 'ids' );
return $this->wanCache->makeKey( 'gadgets-jsonrepo-ids' );
}
/**
@ -170,7 +217,6 @@ class GadgetDefinitionNamespaceRepo extends GadgetRepo {
* @return string
*/
private function getGadgetCacheKey( $id ) {
return $this->wanCache->makeKey(
'gadgets', 'object', md5( $id ), Gadget::GADGET_CLASS_VERSION );
return $this->wanCache->makeKey( 'gadgets-object', $id, Gadget::GADGET_CLASS_VERSION );
}
}

View file

@ -1,8 +1,8 @@
<?php
use MediaWiki\Extension\Gadgets\GadgetDefinitionNamespaceRepo;
use MediaWiki\Extension\Gadgets\GadgetRepo;
use MediaWiki\Extension\Gadgets\MediaWikiGadgetsDefinitionRepo;
use MediaWiki\Extension\Gadgets\MediaWikiGadgetsJsonRepo;
use MediaWiki\MediaWikiServices;
return [
@ -13,7 +13,7 @@ return [
case 'definition':
return new MediaWikiGadgetsDefinitionRepo( $wanCache, $revisionLookup );
case 'json':
return new GadgetDefinitionNamespaceRepo( $wanCache, $revisionLookup );
return new MediaWikiGadgetsJsonRepo( $wanCache, $revisionLookup );
default:
throw new InvalidArgumentException( 'Unexpected value for $wgGadgetsRepo' );
}

View file

@ -102,7 +102,8 @@ class SpecialGadgetUsage extends QueryPage {
'fields' => [
'title' => 'up_property',
'value' => 'COUNT(*)',
'namespace' => NS_GADGET
// Required field, but unused
'namespace' => NS_MEDIAWIKI
],
'conds' => $conds,
'options' => [

View file

@ -99,7 +99,7 @@ class SpecialGadgets extends SpecialPage {
$listOpen = false;
$editDefinitionMessage = $this->getUser()->isAllowed( 'gadgets-definition-edit' )
$editDefinitionMessage = $this->getUser()->isAllowed( 'editsitejs' )
? 'edit'
: 'viewsource';
$editInterfaceMessage = $this->getUser()->isAllowed( 'editinterface' )

View file

@ -15,7 +15,7 @@ use MediaWikiIntegrationTestCase;
class GadgetDefinitionContentHandlerTest extends MediaWikiIntegrationTestCase {
public function testHandler() {
$status = $this->editPage( 'Gadget definition:X1', '{}' );
$status = $this->editPage( 'MediaWiki:Gadgets/X1.json', '{}' );
/** @var RevisionRecord $rev */
$rev = $status->getValue()['revision-record'];
$revText = $rev->getContent( SlotRecord::MAIN )->serialize();

View file

@ -1,40 +0,0 @@
<?php
use MediaWiki\Extension\Gadgets\GadgetDefinitionNamespaceRepo;
/**
* @group Gadgets
* @group Database
*/
class GadgetDefinitionNamespaceRepoTest extends MediaWikiIntegrationTestCase {
/**
* @covers \MediaWiki\Extension\Gadgets\GadgetDefinitionNamespaceRepo
*/
public function testGetGadget() {
$this->editPage( 'Gadget definition:Test',
'{"module":{"pages":["test.js"]}, "settings":{"default":true}}' );
$services = $this->getServiceContainer();
$repo = new GadgetDefinitionNamespaceRepo( $services->getMainWANObjectCache(), $services->getRevisionLookup() );
$gadget = $repo->getGadget( 'Test' );
$this->assertTrue( $gadget->isOnByDefault() );
$this->assertArrayEquals( [ "Gadget:test.js" ], $gadget->getScripts() );
}
/**
* @covers \MediaWiki\Extension\Gadgets\GadgetDefinitionNamespaceRepo
*/
public function testGetGadgetIds() {
$this->editPage( 'Gadget definition:X1',
'{"module":{"pages":["Gadget:test.js"]}, "settings":{"default":true}}' );
$this->editPage( 'Gadget definition:X2',
'{"module":{"pages":["Gadget:test.js"]}, "settings":{"default":true}}' );
$services = $this->getServiceContainer();
$wanCache = $services->getMainWANObjectCache();
$repo = new GadgetDefinitionNamespaceRepo( $wanCache, $services->getRevisionLookup() );
$wanCache->clearProcessCache();
$this->assertArrayEquals( [ 'X1', 'X2' ], $repo->getGadgetIds() );
}
}

View file

@ -0,0 +1,35 @@
<?php
use MediaWiki\Extension\Gadgets\MediaWikiGadgetsJsonRepo;
/**
* @covers \MediaWiki\Extension\Gadgets\MediaWikiGadgetsJsonRepo
* @group Gadgets
* @group Database
*/
class MediaWikiGadgetsJsonRepoTest extends MediaWikiIntegrationTestCase {
public function testGetGadget() {
$this->editPage( 'MediaWiki:Gadgets/test.json',
'{"module":{"pages":["test.js"]}, "settings":{"default":true}}' );
$services = $this->getServiceContainer();
$repo = new MediaWikiGadgetsJsonRepo( $services->getMainWANObjectCache(), $services->getRevisionLookup() );
$gadget = $repo->getGadget( 'test' );
$this->assertTrue( $gadget->isOnByDefault() );
$this->assertArrayEquals( [ "MediaWiki:Gadget-test.js" ], $gadget->getScripts() );
}
public function testGetGadgetIds() {
$this->editPage( 'MediaWiki:Gadgets/X1.json',
'{"module":{"pages":["MediaWiki:Gadget-test.js"]}, "settings":{"default":true}}' );
$this->editPage( 'MediaWiki:Gadgets/X2.json',
'{"module":{"pages":["MediaWiki:Gadget-test.js"]}, "settings":{"default":true}}' );
$services = $this->getServiceContainer();
$wanCache = $services->getMainWANObjectCache();
$repo = new MediaWikiGadgetsJsonRepo( $wanCache, $services->getRevisionLookup() );
$wanCache->clearProcessCache();
$this->assertArrayEquals( [ 'X1', 'X2' ], $repo->getGadgetIds() );
}
}