diff --git a/Gadgets.namespaces.php b/Gadgets.namespaces.php
deleted file mode 100644
index dff8ea2f..00000000
--- a/Gadgets.namespaces.php
+++ /dev/null
@@ -1,442 +0,0 @@
- 'Гаджет',
- 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',
-];
diff --git a/extension.json b/extension.json
index c87c284a..89267ba0 100644
--- a/extension.json
+++ b/extension.json
@@ -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"
diff --git a/i18n/en.json b/i18n/en.json
index 905c8b28..51036467 100644
--- a/i18n/en.json
+++ b/i18n/en.json
@@ -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 ?withgadget
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 ?withgadget
query parameter."
}
diff --git a/i18n/qqq.json b/i18n/qqq.json
index 76da9ff2..4ed142a8 100644
--- a/i18n/qqq.json
+++ b/i18n/qqq.json
@@ -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."
}
diff --git a/includes/CodeEditorHooks.php b/includes/CodeEditorHooks.php
index aeda7483..a8ccac8e 100644
--- a/includes/CodeEditorHooks.php
+++ b/includes/CodeEditorHooks.php
@@ -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
diff --git a/includes/Content/GadgetDefinitionContentHandler.php b/includes/Content/GadgetDefinitionContentHandler.php
index b62dcdb0..1a06dac1 100644
--- a/includes/Content/GadgetDefinitionContentHandler.php
+++ b/includes/Content/GadgetDefinitionContentHandler.php
@@ -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 ) ) {
diff --git a/includes/Gadget.php b/includes/Gadget.php
index 37cd0a6e..41f7b868 100644
--- a/includes/Gadget.php
+++ b/includes/Gadget.php
@@ -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'],
diff --git a/includes/GadgetRepo.php b/includes/GadgetRepo.php
index 75dd3119..9aba82bf 100644
--- a/includes/GadgetRepo.php
+++ b/includes/GadgetRepo.php
@@ -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 );
}
/**
diff --git a/includes/Hooks.php b/includes/Hooks.php
index eab3c062..e3045c77 100644
--- a/includes/Hooks.php
+++ b/includes/Hooks.php
@@ -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/.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;
}
}
diff --git a/includes/MediaWikiGadgetsDefinitionRepo.php b/includes/MediaWikiGadgetsDefinitionRepo.php
index 69fdf330..564372e2 100644
--- a/includes/MediaWikiGadgetsDefinitionRepo.php
+++ b/includes/MediaWikiGadgetsDefinitionRepo.php
@@ -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 );
diff --git a/includes/GadgetDefinitionNamespaceRepo.php b/includes/MediaWikiGadgetsJsonRepo.php
similarity index 62%
rename from includes/GadgetDefinitionNamespaceRepo.php
rename to includes/MediaWikiGadgetsJsonRepo.php
index 1ca694ba..1a54959c 100644
--- a/includes/GadgetDefinitionNamespaceRepo.php
+++ b/includes/MediaWikiGadgetsJsonRepo.php
@@ -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/.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 );
}
}
diff --git a/includes/ServiceWiring.php b/includes/ServiceWiring.php
index 3a771c3d..b76cbb54 100644
--- a/includes/ServiceWiring.php
+++ b/includes/ServiceWiring.php
@@ -1,8 +1,8 @@
[
'title' => 'up_property',
'value' => 'COUNT(*)',
- 'namespace' => NS_GADGET
+ // Required field, but unused
+ 'namespace' => NS_MEDIAWIKI
],
'conds' => $conds,
'options' => [
diff --git a/includes/Special/SpecialGadgets.php b/includes/Special/SpecialGadgets.php
index 9c2a5ce4..dbeb5770 100644
--- a/includes/Special/SpecialGadgets.php
+++ b/includes/Special/SpecialGadgets.php
@@ -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' )
diff --git a/tests/phpunit/integration/GadgetDefinitionContentHandlerTest.php b/tests/phpunit/integration/GadgetDefinitionContentHandlerTest.php
index fdb38f61..d1590f77 100644
--- a/tests/phpunit/integration/GadgetDefinitionContentHandlerTest.php
+++ b/tests/phpunit/integration/GadgetDefinitionContentHandlerTest.php
@@ -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();
diff --git a/tests/phpunit/integration/GadgetDefinitionNamespaceRepoTest.php b/tests/phpunit/integration/GadgetDefinitionNamespaceRepoTest.php
deleted file mode 100644
index 3e253934..00000000
--- a/tests/phpunit/integration/GadgetDefinitionNamespaceRepoTest.php
+++ /dev/null
@@ -1,40 +0,0 @@
-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() );
- }
-}
diff --git a/tests/phpunit/integration/MediaWikiGadgetsJsonRepoTest.php b/tests/phpunit/integration/MediaWikiGadgetsJsonRepoTest.php
new file mode 100644
index 00000000..b5103dfd
--- /dev/null
+++ b/tests/phpunit/integration/MediaWikiGadgetsJsonRepoTest.php
@@ -0,0 +1,35 @@
+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() );
+ }
+}