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 b73c97aa..e24410c4 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() ); + } +}