Wikipedia testwiki https://test.wikipedia.org/wiki/Main_Page MediaWiki 1.46.0-wmf.24 first-letter Media Special Talk User User talk Wikipedia Wikipedia talk File File talk MediaWiki MediaWiki talk Template Template talk Help Help talk Category Category talk Thread Thread talk Summary Summary talk Test namespace 1 Test namespace 1 talk Test namespace 2 Test namespace 2 talk Draft Draft talk Campaign Campaign talk TimedText TimedText talk Module Module talk SecurePoll SecurePoll talk CNBanner CNBanner talk Translations Translations talk Event Event talk Topic Newsletter Newsletter talk Template:No article text 10 78344 739045 738935 2026-04-21T22:49:29Z Sheffalump 71152 739045 wikitext text/x-wiki <div class="mw-parser-output"><!-- don't touch this div to the left, it makes TemplateStyles vroom vroom --> {{New page DYM}} {{ #ifeq: {{NAMESPACE}} | {{TALKSPACE}} |{{#ifexist: {{SUBJECTPAGENAME}}|This is the talk page for [[:{{SUBJECTPAGENAME}}]].|[[:{{SUBJECTPAGENAME}}]] has not yet been created. {{Viewing talk page without subject}}|}}}} {{fmbox | type = system | id = noarticletext | image = none | textstyle = padding: 0.6em 0.9em; <!--Large box needs more padding--> | text = {{#tag:strong|WARNING:}} {{ #ifeq: {{ #ifeq: {{FULLPAGENAME}} | Template:No article text || }} | <!--Mainspace sister project infobox--> | {{No article text/sister projects}} }}{{ #ifeq: {{NAMESPACE}} | {{ns:User talk}} | {{#tag:strong|No messages}} have been posted for {{BASEPAGENAME}} yet. | {{#tag:strong|Wikipedia does not contain {{ #switch: {{NAMESPACE}} | {{ns:0}} = a {{#tag:em|[[{{ns:Project}}:Using pages without namespaces|page]]}} | {{ns:Talk}} = a {{#tag:em|[[{{ns:Help}}:Using talk pages|discussion page]]}} | {{TALKSPACE}} = the {{#tag:em|[[{{ns:Help}}:Using talk pages|{{SUBJECTSPACE}}'s discussion page]]}} | {{ns:Category}} = a {{#tag:em|[[{{ns:Project}}:Categorization|category]]}} | {{ns:Help}} = a {{#tag:em|[[{{ns:Help}}:Contents|help page]]}} | {{ns:File}} = a {{#tag:em|[[{{ns:Project}}:Files to upload|file]]}} | {{ns:Portal}} = a {{#tag:em|[[{{ns:Project}}:Portal|portal]]}} | {{ns:Template}} = a {{#tag:em|[[{{ns:Project}}:Template messages|template]]}} | {{ns:User}} = a {{#tag:em|[[{{ns:Project}}:User pages|user page]]}} | {{ns:Project}} = a {{#tag:em|[[{{ns:Project}}:Project namespace|project page]]}} | {{ns:MediaWiki}} = a {{#tag:em|[[Special:AllMessages|system message]]}} | #default = a {{#tag:em|[[{{ns:Project}}:Namespaces|{{NAMESPACE}} page]]}} }} with this exact name yet.}} {{ #ifeq: {{#invoke:String|replace|source={{PAGENAME}}|­}} | {{#invoke:String|replace|source={{SUBPAGENAME}}|­}} | {{ #switch: {{NAMESPACE}} | {{ns:0}} = Please {{plain link|url=https://test.wikipedia.org/w/index.php?search={{urlencode:{{#titleparts:{{#invoke:String|replace|source={{PAGENAME}}|­}}}}}}&title=Special%3ASearch&fulltext=1|name=search for ''{{#invoke:String|replace|source={{PAGENAME}}|­}}'' in Test Wikipedia}} to check for alternative titles, names, or spellings. | {{ns:Talk}} = Before creating this page, please verify that a page called [[{{PAGENAME}}]] exists. | {{TALKSPACE}} = Before creating this page, please verify that [[:{{SUBJECTPAGENAME}}]] is already made. | {{ns:Category}} = Please browse the [[Portal:Contents|existing categories]] to check if this category is covered under another name. | {{ns:Help}} = Please browse the [[{{ns:Help}}:Contents|existing help pages]] to check if this help topic is covered under another name. | {{ns:File}} = Please do not manually create this page. If you want to upload ''File:{{PAGENAME}}'', Please see the [[{{ns:Project}}:Files to upload|Files to upload]] for instructions & tutorials. | {{ns:Portal}} = Please browse the [[{{ns:Portal}}:Contents/Portals|existing portals]] to check for similar topics. | {{ns:Template}} = Please browse the [[{{ns:Project}}:Template messages|existing templates]] to check if this standardized message is available under another name. | {{ns:User}} = In general, this page should be created and edited by [[User:{{PAGENAME}}]]. If you're already registered, Please [[Special:UserLogin|log in]]. If you don't have an account, [[Special:CreateAccount|create one]]. If you are {{PAGENAME}}, click [[Special:Edit/User:{{PAGENAME}}|create this page]]. If you are not {{PAGENAME}}, don't click "create this page". | {{ns:Project}} = Please browse the [[{{ns:Project}}:List of policies and guidelines|existing policies and guidelines]] or [[Special:Search/{{ns:Project}}:{{PAGENAME}}|search]] for similar existing project pages. | {{ns:MediaWiki}} = Please browse the [[Special:AllMessages|existing system messages]] to check if this Non-CSS, Non-JavaScript, Non-JSON, CSS, JavaScript, & JSON pages are available under another name. | #default = Please browse the [[{{ns:Project}}:Namespaces|existing {{NAMESPACE}} pages]] to check if this {{NAMESPACE}} namespace is available under another name. }} | {{ #ifeq: {{{nopermission}}} | yes |You do not have permission to edit pages in the {{#if: {{NAMESPACE}} | '''[[Wikipedia:Namespaces|{{NAMESPACE}}]]''' namespace | '''[[Wikipedia:Namespaces|Page]]''' namespace }}. Please [{{fullurl:Special:UserLogin|returnto={{ urlencode: {{#invoke:String|replace|source={{FULLPAGENAME}}|­}} }}}} log in] or [{{fullurl:Special:UserLogin/signup|returnto={{ urlencode: {{#invoke:String|replace|source={{FULLPAGENAME}}|­}} }}}} sign up] if you want to create this page. (This page is currently protected so only administrators, system administrators, template editors, extended confirmed users, page movers, autoconfirmed users, & logged in users can make it, '''not''' temporary accounts or unregistered (IP) users). (If you're logged out, {{SITENAME}} has restricted the ability to create new pages. You can go back and edit an existing page, or [[Special:UserLogin|log in or create an account]]. If you're logged in, You do not have permission to create new pages.) Please see [[{{ns:Project}}:Subpages|Subpages]] for subpages if you do not create it because this isn't needed. To protect the page, click [[Special:Protect/{{FULLPAGENAME}}|protect]].| Before creating this page in the {{#if: {{NAMESPACE}} | '''[[Wikipedia:Namespaces|{{NAMESPACE}}]]''' namespace | '''[[Wikipedia:Namespaces|Page]]''' namespace }}, please see [[{{ns:Project}}:Subpages|Subpages]] for subpages. To protect the page, click [[Special:Protect/{{FULLPAGENAME}}|protect]].}} }} }}{{ #ifeq: {{{nopermission}}} | yes |* {{ #switch: {{#invoke:Effective protection level|create|{{#invoke:String|replace|source={{FULLPAGENAME}}|­}}}} | sysop = Administrators can't edit this {{NAMESPACE}} page, but still be able to edit pages by autoconfirmed users, users, anonymous users, & temporally accounts. You will <span class="anononly">need to [{{fullurl:Special:UserLogin|returnto={{ urlencode: {{#invoke:String|replace|source={{FULLPAGENAME}}|­}} }}}} log in or create an account] and will</span> be [[Wikipedia:Administrators|administrators]] to create new pages, system messages, & JSON pages. | interfaceadmin = System administrators can't edit this {{NAMESPACE}} page, but still be able to edit pages by autoconfirmed users, users, anonymous users, & temporally accounts. You will <span class="anononly">need to [{{fullurl:Special:UserLogin|returnto={{ urlencode: {{#invoke:String|replace|source={{FULLPAGENAME}}|­}} }}}} log in or create an account] and will </span>be [[Wikipedia:System administrators|system administrators]] to create new CSS & JavaScript pages. | templateeditor = Template editors & administrators can't edit this {{NAMESPACE}} page, but still be able to edit pages by autoconfirmed users, users, anonymous users, & temporally accounts. You will <span class="anononly">need to [{{fullurl:Special:UserLogin|returnto={{ urlencode: {{#invoke:String|replace|source={{FULLPAGENAME}}|­}} }}}} log in or create an account] and will</span> be [[WP:Template editor|template editors]] to create new pages. | extendedconfirmed = Extended confirmed users & administrators can't edit this {{NAMESPACE}} page, but still be able to edit pages by autoconfirmed users, users, anonymous users, & temporally accounts. You will <span class="anononly">need to [{{fullurl:Special:UserLogin|returnto={{ urlencode: {{#invoke:String|replace|source={{FULLPAGENAME}}|­}} }}}} log in or create an account] and will</span> be [[Wikipedia:User access levels#Extendedconfirmed|extended confirmed users]] to create new pages. | autoconfirmed = Autoconfirmed users can't edit this {{NAMESPACE}} page, but still be able to edit pages by users, anonymous users, & temporally accounts. You will <span class="anononly">need to [{{fullurl:Special:UserLogin|returnto={{ urlencode: {{#invoke:String|replace|source={{FULLPAGENAME}}|­}} }}}} log in or create an account] and will </span>be [[WP:User access levels#Autoconfirmed users|autoconfirmed users]] to create new pages. (After 4 days & 10 edits on English Wikipedia.) | user = Some users can't edit this {{NAMESPACE}} page, but still be able to edit pages by anonymous users & temporally accounts. You will need to [{{fullurl:Special:UserLogin|returnto={{ urlencode: {{#invoke:String|replace|source={{FULLPAGENAME}}|­}} }}}} log in or create an account] to make this page. {{#ifeq:{{NAMESPACE}}|{{ns:Category}}|Or, you can [[Wikipedia:Articles for creation/Categories|request the creation of a new category]].}} | #default = Users with the "Create" permission can't edit this {{NAMESPACE}} page. (You do not have permission to create this page when not logged in). You will need to [{{fullurl:Special:UserLogin|returnto={{ urlencode: {{#invoke:String|replace|source={{FULLPAGENAME}}|­}} }}}} log in or create an account] and will be [[WP:User access levels#Autoconfirmed users|autoconfirmed users]] to make your own page. }} |{{#ifeq:{{#invoke:Title blacklist|main|action=create|pagename={{#invoke:String|replace|source={{FULLPAGENAME}}|­}}}}|templateeditor|* Administrators, template editors, & page movers can't edit this {{NAMESPACE}} page, but still be able to edit pages by autoconfirmed users, users, anonymous users, & temporally accounts. You will need to [{{fullurl:Special:UserLogin|returnto={{ urlencode: {{#invoke:String|replace|source={{FULLPAGENAME}}|­}} }}}} log in or create an account] and will be [[Wikipedia:Administrators|administrators]], [[Wikipedia:Template editors|template editors]], & [[Wikipedia:Page movers|page movers]] to create new ones.|* ''' {{ #switch: {{NAMESPACE}} | {{ns:3}} = {{#ifeq:{{ROOTPAGENAME}}|{{PAGENAME}}|[[Special:Edit/{{FULLPAGENAME}}|Post a message to ''{{#invoke:String|replace|source={{PAGENAME}}|­}}]]''|[[Special:Edit/{{FULLPAGENAME}}|Start the ''{{#invoke:String|replace|source={{FULLPAGENAME}}|­}}'' page]] or [[Special:NewSection/{{FULLPAGENAME}}|leave a message about the ''{{#invoke:String|replace|source={{SUBJECTPAGENAME}}|­}}]]''}} | {{ns:5}} | {{ns:7}} | {{ns:9}} | {{ns:11}} | {{ns:13}} | {{ns:15}} | {{ns:101}} | {{ns:119}} | {{ns:711}} | {{ns:829}} | {{ns:1}} = [[Special:Edit/{{FULLPAGENAME}}|Start the ''{{#invoke:String|replace|source={{FULLPAGENAME}}|­}}'' page]] or [[Special:NewSection/{{FULLPAGENAME}}|leave a message about the ''{{#invoke:String|replace|source={{SUBJECTPAGENAME}}|­}}]]'' | {{ns:Category}} = [[Special:Edit/{{FULLPAGENAME}}|Start the ''{{#invoke:String|replace|source={{FULLPAGENAME}}|}}'']] | {{ns:Project}} = [[Special:Edit/{{FULLPAGENAME}}|Start the ''{{#invoke:String|replace|source={{FULLPAGENAME}}|­}}'' page]] or [[Special:NewSection/{{FULLPAGENAME}}|start a discussion about the ''{{#invoke:String|replace|source={{FULLPAGENAME}}|­}}]]'' | #default = [[Special:Edit/{{FULLPAGENAME}}|Start the ''{{#invoke:String|replace|source={{FULLPAGENAME}}|}}'' page]] }}''' {{ #if: {{NAMESPACE}} |by using the '''"[[Wikipedia:Namespaces|{{NAMESPACE}}]]"''' namespace|by using the '''"[[Wikipedia:Namespaces|Page]]"''' namespace, using the [[Wikipedia:Article wizard|Article Wizard]] if you want to create it & submit it for review, or [[{{ns:Project}}:Requested articles|add a request for the new page]] }}.}} }}{{ #switch: {{NAMESPACE}} | {{ns:0}} = * {{plain link|url=https://test.wikipedia.org/w/index.php?search={{urlencode:{{#titleparts:{{#invoke:String|replace|source={{PAGENAME}}|­}}}}}}&title=Special%3ASearch&fulltext=1&ns{{NAMESPACENUMBER}}=1|name=Search for "''{{#invoke:String|replace|source={{PAGENAME}}|­}}''"}} in existing pages. * [[wiktionary:en:Special:Search/{{FULLPAGENAME}}|Look for "{{FULLPAGENAME}}"]] in Wiktionary, our sister dictionary project. * [[commons:Special:Search/{{FULLPAGENAME}}|Look for "{{FULLPAGENAME}}"]] in the Wikimedia Commons, our repository for free images, music, sound, and video. | {{ns:User}} = * [[{{ns:Special}}:WhatLinksHere/{{#invoke:String|replace|source={{FULLPAGENAME}}|­}}|Look for pages within the Test Wikipedia that link to this user page]]. | {{ns:User talk}} = * [[{{ns:Special}}:WhatLinksHere/{{#invoke:String|replace|source={{FULLPAGENAME}}|­}}|Look for pages within the Test Wikipedia that link to this user talk page]]. | {{ns:Category}} = * {{plain link|url=https://test.wikipedia.org/w/index.php?search={{urlencode:{{#titleparts:{{#invoke:String|replace|source={{PAGENAME}}|­}}}}}}&title=Special%3ASearch&fulltext=1&ns{{NAMESPACENUMBER}}=1|name=Search for "''{{#invoke:String|replace|source={{PAGENAME}}|­}}''"}} in existing categories. * [[wiktionary:en:Special:Search/{{FULLPAGENAME}}|Look for "{{FULLPAGENAME}}"]] in Wiktionary, our sister dictionary project. * [[commons:Special:Search/{{FULLPAGENAME}}|Look for "{{FULLPAGENAME}}"]] in the Wikimedia Commons, our repository for free images, music, sound, and video. | {{ns:File}} = * {{plain link|url=https://test.wikipedia.org/w/index.php?search={{urlencode:{{#titleparts:{{#invoke:String|replace|source={{PAGENAME}}|­}}}}}}&title=Special%3ASearch&fulltext=1&ns{{NAMESPACENUMBER}}=1|name=Search for "''{{#invoke:String|replace|source={{PAGENAME}}|­}}''"}} in existing files. * [[commons:Special:Search/{{FULLPAGENAME}}|Look for "{{FULLPAGENAME}}"]] in the Wikimedia Commons, our repository for free images, music, sound, and video. | {{ns:Template}} = * {{plain link|url=https://test.wikipedia.org/w/index.php?search={{urlencode:{{#titleparts:{{#invoke:String|replace|source={{PAGENAME}}|­}}}}}}&title=Special%3ASearch&fulltext=1&ns{{NAMESPACENUMBER}}=1|name=Search for "''{{#invoke:String|replace|source={{PAGENAME}}|­}}''"}} in existing templates. * [[wikimedia:Special:Search/{{FULLPAGENAME}}|Look for "{{FULLPAGENAME}}"]] in Wikimedia, the Free Templates, Categories, & More! | #default = * {{plain link|url=https://test.wikipedia.org/w/index.php?search={{urlencode:{{#titleparts:{{#invoke:String|replace|source={{PAGENAME}}|­}}}}}}&title=Special%3ASearch&fulltext=1&ns{{NAMESPACENUMBER}}=1|name=Search for "''{{#invoke:String|replace|source={{PAGENAME}}|­}}''"}} in existing {{#if: {{NAMESPACE}} | pages with the '''"[[{{ns:Project}}:Namespaces|{{NAMESPACE}}]]"''' namespace | pages without using [[{{ns:Project}}:Namespaces|namespaces]] }}. * [[{{ns:Special}}:WhatLinksHere/{{#invoke:String|replace|source={{FULLPAGENAME}}|­}}|Look for pages within the Test Wikipedia that link to this title]]. }} * {{ #ifeq: {{NAMESPACE}} | {{TALKSPACE}} | You can go back to your [[:{{SUBJECTPAGENAME}}|subject page]] | Please discuss changes on your [[{{TALKPAGENAME}}|talk page]] }}. <div id="noarticletext_technical"> ---- '''Other reasons that may be displayed this message:''' * If {{ #ifeq: {{NAMESPACE}} | {{ns:File}} | a file | a page }} was recently edited here, it may be invisible. (Because of a delay in updating the database.) You can wait a few minutes to complete, you can [[Special:Purge/{{FULLPAGENAME}}|click it]] for purging, or you may want to [[Special:Protect/{{FULLPAGENAME}}|protect]] this page. You can also want to [[Special:Edit/{{FULLPAGENAME}}|edit this page]] or [[Special:Delete/{{FULLPAGENAME}}|delete this page]]. * Titles on the Test Wikipedia is in the '''[[w:en:Case sensitivity|case sensitivity]]''' except for this first character; please {{plain link|url=https://test.wikipedia.org/w/index.php?search={{urlencode:{{#titleparts:{{#invoke:String|replace|source={{FULLPAGENAME}}|­}}}}}}&title=Special%3ASearch&fulltext=1|name=check the Test Wikipedia's alternative capitalizations}} and consider adding some [[Wikipedia:Redirects|redirects]] here to the correct title. If the page you are looking for is not TestSite, see its corresponding [[w:en:Main Page|language Wikipedia]]. If the page is not a [[w:en:test wiki|test wiki]], check one of the [[wikimedia:Main Page|other Foundation wikis]]. * If this page has been deleted, try [{{fullurl:Special:Log/delete|page={{#invoke:String|replace|source={{FULLPAGENAMEE}}|­}}}} checking the '''deletion log'''], and see [[Wikipedia:Why was the page I created deleted?|the Why was the page I created deleted?]] for possible reasons. </div> }} <!--End fmbox --><!--Start book box-->{{#if:{{#invoke:String|match|{{FULLPAGENAME}}|^Book:|nomatch= }}{{#invoke:String|match|{{FULLPAGENAME}}|^Book talk:|nomatch= }}|{{fmbox|type=system|text=<strong>This page may have existed as part of the former book & talk namespace.</strong> If so it was likely moved to [[{{#invoke:String|replace|{{#invoke:String|replace|{{FULLPAGENAME}}|^Book talk:|Book:|plain=False}}|^Book:|Wikipedia:Books/archive/|plain=False}}]] before being deleted. See [[Wikipedia:Books]] for more information.}}}}<!--End book box--> </div> == {{ #switch: {{NAMESPACE}} | {{ns:0}} = Page | {{ns:Talk}} = [[{{ns:Help}}:Using talk pages|Discussion page]] | {{TALKSPACE}} = [[{{ns:Help}}:Using talk pages|{{SUBJECTSPACE}}'s Discussion page]] | {{ns:Category}} = [[{{ns:Project}}:Categorization|Category]] | {{ns:Help}} = [[{{ns:Help}}:Contents|Help page]] | {{ns:File}} = [[{{ns:Project}}:Files to upload|File]] | {{ns:Portal}} = [[{{ns:Project}}:Portal|Portal]] | {{ns:Template}} = [[{{ns:Project}}:Template messages|Template]] | {{ns:User}} = [[{{ns:Project}}:User pages|User page]] | {{ns:Project}} = [[{{ns:Project}}:Project namespace|Project page]] | {{ns:MediaWiki}} = [[Special:AllMessages|System message]] | #default = {{NAMESPACE}} page}} not showing up? == Reload the page you just created "'''{{FULLPAGENAME}}'''." <small>You may also [[Wikipedia:Administrators' noticeboard|contact an administrator]] before recreating this page.</small> If you can't find the page, you can [[Special:Search/{{FULLPAGENAME}}|search for an existing page]] or [[Special:Edit/{{FULLPAGENAME}}|create it]]. {{ #ifeq: {{{nopermission}}} | yes |{{fmbox | type = warning | id = noarticletext | image = none | text = You do not have permission to create this page. It may have been restricted from creation.}}|{{fmbox | type = system | id = noarticletext | image = none | text = If you can't find {{FULLPAGENAME}}, you can also include the <span class="planlinks">[{{fullurl:{{FULLPAGENAME}}|veaction=edit}} visual editor]</span>, {{ #ifeq: {{NAMESPACE}} | {{TALKSPACE}} | the <span class="planlinks">[{{fullurl:{{FULLPAGENAME}}|action=edit&veswitched=1}} source editor]</span>, or [[Special:NewSection/{{FULLPAGENAME}}|create a new section]] | or the <span class="planlinks">[{{fullurl:{{FULLPAGENAME}}|action=edit&veswitched=1}} source editor]</span> }} for editing.}}}} <noinclude> {{documentation}} </noinclude> elm7td7usxzbp1xurwqbmaco53q3uuo 739046 739045 2026-04-21T22:55:42Z Sheffalump 71152 739046 wikitext text/x-wiki <div class="mw-parser-output"><!-- don't touch this div to the left, it makes TemplateStyles vroom vroom --> {{New page DYM}} {{ #ifeq: {{NAMESPACE}} | {{TALKSPACE}} |{{#ifexist: {{SUBJECTPAGENAME}}|This is the talk page for [[:{{SUBJECTPAGENAME}}]].|[[:{{SUBJECTPAGENAME}}]] has not yet been created. {{Viewing talk page without subject}}|}}}} {{fmbox | type = system | id = noarticletext | image = none | textstyle = padding: 0.6em 0.9em; <!--Large box needs more padding--> | text = {{#tag:strong|WARNING:}} {{ #ifeq: {{ #ifeq: {{FULLPAGENAME}} | Template:No article text || }} | <!--Mainspace sister project infobox--> | {{No article text/sister projects}} }}{{ #ifeq: {{NAMESPACE}} | {{ns:User talk}} | {{#tag:strong|No messages}} have been posted for {{BASEPAGENAME}} yet. | {{#tag:strong|Wikipedia does not contain {{ #switch: {{NAMESPACE}} | {{ns:0}} = a {{#tag:em|[[{{ns:Project}}:Using pages without namespaces|page]]}} | {{ns:Talk}} = a {{#tag:em|[[{{ns:Help}}:Using talk pages|discussion page]]}} | {{TALKSPACE}} = the {{#tag:em|[[{{ns:Help}}:Using talk pages|{{SUBJECTSPACE}}'s discussion page]]}} | {{ns:Category}} = a {{#tag:em|[[{{ns:Project}}:Categorization|category]]}} | {{ns:Help}} = a {{#tag:em|[[{{ns:Help}}:Contents|help page]]}} | {{ns:File}} = a {{#tag:em|[[{{ns:Project}}:Files to upload|file]]}} | {{ns:Portal}} = a {{#tag:em|[[{{ns:Project}}:Portal|portal]]}} | {{ns:Template}} = a {{#tag:em|[[{{ns:Project}}:Template messages|template]]}} | {{ns:User}} = a {{#tag:em|[[{{ns:Project}}:User pages|user page]]}} | {{ns:Project}} = a {{#tag:em|[[{{ns:Project}}:Project namespace|project page]]}} | {{ns:MediaWiki}} = a {{#tag:em|[[Special:AllMessages|system message]]}} | #default = a {{#tag:em|[[{{ns:Project}}:Namespaces|{{NAMESPACE}} page]]}} }} with this exact name yet.}} {{ #ifeq: {{#invoke:String|replace|source={{PAGENAME}}|­}} | {{#invoke:String|replace|source={{SUBPAGENAME}}|­}} | {{ #switch: {{NAMESPACE}} | {{ns:0}} = Please {{plain link|url=https://test.wikipedia.org/w/index.php?search={{urlencode:{{#titleparts:{{#invoke:String|replace|source={{PAGENAME}}|­}}}}}}&title=Special%3ASearch&fulltext=1|name=search for ''{{#invoke:String|replace|source={{PAGENAME}}|­}}'' in Test Wikipedia}} to check for alternative titles, names, or spellings. | {{ns:Talk}} = Before creating this page, please verify that a page called [[{{PAGENAME}}]] exists. | {{TALKSPACE}} = Before creating this page, please verify that [[:{{SUBJECTPAGENAME}}]] is already made. | {{ns:Category}} = Please browse the [[Portal:Contents|existing categories]] to check if this category is covered under another name. | {{ns:Help}} = Please browse the [[{{ns:Help}}:Contents|existing help pages]] to check if this help topic is covered under another name. | {{ns:File}} = Please do not manually create this page. If you want to upload ''File:{{PAGENAME}}'', Please see the [[{{ns:Project}}:Files to upload|Files to upload]] for instructions & tutorials. | {{ns:Portal}} = Please browse the [[{{ns:Portal}}:Contents/Portals|existing portals]] to check for similar topics. | {{ns:Template}} = Please browse the [[{{ns:Project}}:Template messages|existing templates]] to check if this standardized message is available under another name. | {{ns:User}} = In general, this page should be created and edited by [[User:{{PAGENAME}}]]. If you're already registered, Please [[Special:UserLogin|log in]]. If you don't have an account, [[Special:CreateAccount|create one]]. If you are {{PAGENAME}}, click [[Special:Edit/User:{{PAGENAME}}|create this page]]. If you are not {{PAGENAME}}, don't click "create this page". | {{ns:Project}} = Please browse the [[{{ns:Project}}:List of policies and guidelines|existing policies and guidelines]] or [[Special:Search/{{ns:Project}}:{{PAGENAME}}|search]] for similar existing project pages. | {{ns:MediaWiki}} = Please browse the [[Special:AllMessages|existing system messages]] to check if this Non-CSS, Non-JavaScript, Non-JSON, CSS, JavaScript, & JSON pages are available under another name. | #default = Please browse the [[{{ns:Project}}:Namespaces|existing {{NAMESPACE}} pages]] to check if this {{NAMESPACE}} namespace is available under another name. }} | {{ #ifeq: {{{nopermission}}} | yes |You do not have permission to edit pages in the {{#if: {{NAMESPACE}} | '''[[Wikipedia:Namespaces|{{NAMESPACE}}]]''' namespace | '''[[Wikipedia:Namespaces|Page]]''' namespace }}. Please [{{fullurl:Special:UserLogin|returnto={{ urlencode: {{#invoke:String|replace|source={{FULLPAGENAME}}|­}} }}}} log in] or [{{fullurl:Special:UserLogin/signup|returnto={{ urlencode: {{#invoke:String|replace|source={{FULLPAGENAME}}|­}} }}}} sign up] if you want to create this page. (This page is currently protected so only administrators, system administrators, template editors, extended confirmed users, page movers, autoconfirmed users, & logged in users can make it, '''not''' temporary accounts or unregistered (IP) users). (If you're logged out, {{SITENAME}} has restricted the ability to create new pages. You can go back and edit an existing page, or [[Special:UserLogin|log in or create an account]]. If you're logged in, You do not have permission to create new pages.) Please see [[{{ns:Project}}:Subpages|Subpages]] for subpages if you do not create it because this isn't needed. To protect the page, click [[Special:Protect/{{FULLPAGENAME}}|protect]].| Before creating this page in the {{#if: {{NAMESPACE}} | '''[[Wikipedia:Namespaces|{{NAMESPACE}}]]''' namespace | '''[[Wikipedia:Namespaces|Page]]''' namespace }}, please see [[{{ns:Project}}:Subpages|Subpages]] for subpages. To protect the page, click [[Special:Protect/{{FULLPAGENAME}}|protect]].}} }} }}{{ #ifeq: {{{nopermission}}} | yes |* {{ #switch: {{#invoke:Effective protection level|create|{{#invoke:String|replace|source={{FULLPAGENAME}}|­}}}} | sysop = Administrators can't edit this {{NAMESPACE}} page, but still be able to edit pages by autoconfirmed users, users, anonymous users, & temporally accounts. You will <span class="anononly">need to [{{fullurl:Special:UserLogin|returnto={{ urlencode: {{#invoke:String|replace|source={{FULLPAGENAME}}|­}} }}}} log in or create an account] and will</span> be [[Wikipedia:Administrators|administrators]] to create new pages, system messages, & JSON pages. | interfaceadmin = System administrators can't edit this {{NAMESPACE}} page, but still be able to edit pages by autoconfirmed users, users, anonymous users, & temporally accounts. You will <span class="anononly">need to [{{fullurl:Special:UserLogin|returnto={{ urlencode: {{#invoke:String|replace|source={{FULLPAGENAME}}|­}} }}}} log in or create an account] and will </span>be [[Wikipedia:System administrators|system administrators]] to create new CSS & JavaScript pages. | templateeditor = Template editors & administrators can't edit this {{NAMESPACE}} page, but still be able to edit pages by autoconfirmed users, users, anonymous users, & temporally accounts. You will <span class="anononly">need to [{{fullurl:Special:UserLogin|returnto={{ urlencode: {{#invoke:String|replace|source={{FULLPAGENAME}}|­}} }}}} log in or create an account] and will</span> be [[WP:Template editor|template editors]] to create new pages. | extendedconfirmed = Extended confirmed users & administrators can't edit this {{NAMESPACE}} page, but still be able to edit pages by autoconfirmed users, users, anonymous users, & temporally accounts. You will <span class="anononly">need to [{{fullurl:Special:UserLogin|returnto={{ urlencode: {{#invoke:String|replace|source={{FULLPAGENAME}}|­}} }}}} log in or create an account] and will</span> be [[Wikipedia:User access levels#Extendedconfirmed|extended confirmed users]] to create new pages. | autoconfirmed = Autoconfirmed users can't edit this {{NAMESPACE}} page, but still be able to edit pages by users, anonymous users, & temporally accounts. You will <span class="anononly">need to [{{fullurl:Special:UserLogin|returnto={{ urlencode: {{#invoke:String|replace|source={{FULLPAGENAME}}|­}} }}}} log in or create an account] and will </span>be [[WP:User access levels#Autoconfirmed users|autoconfirmed users]] to create new pages. (After 4 days & 10 edits on English Wikipedia.) | user = Some users can't edit this {{NAMESPACE}} page, but still be able to edit pages by anonymous users & temporally accounts. You will need to [{{fullurl:Special:UserLogin|returnto={{ urlencode: {{#invoke:String|replace|source={{FULLPAGENAME}}|­}} }}}} log in or create an account] to make this page. {{#ifeq:{{NAMESPACE}}|{{ns:Category}}|Or, you can [[Wikipedia:Articles for creation/Categories|request the creation of a new category]].}} | #default = Users with the "Create" permission can't edit this {{NAMESPACE}} page. (You do not have permission to create this page when not logged in). You will need to [{{fullurl:Special:UserLogin|returnto={{ urlencode: {{#invoke:String|replace|source={{FULLPAGENAME}}|­}} }}}} log in or create an account] and will be [[WP:User access levels#Autoconfirmed users|autoconfirmed users]] to make your own page. }} |{{#ifeq:{{#invoke:Title blacklist|main|action=create|pagename={{#invoke:String|replace|source={{FULLPAGENAME}}|­}}}}|templateeditor|* Administrators, template editors, & page movers can't edit this {{NAMESPACE}} page, but still be able to edit pages by autoconfirmed users, users, anonymous users, & temporally accounts. You will need to [{{fullurl:Special:UserLogin|returnto={{ urlencode: {{#invoke:String|replace|source={{FULLPAGENAME}}|­}} }}}} log in or create an account] and will be [[Wikipedia:Administrators|administrators]], [[Wikipedia:Template editors|template editors]], & [[Wikipedia:Page movers|page movers]] to create new ones.|* ''' {{ #switch: {{NAMESPACE}} | {{ns:3}} = {{#ifeq:{{ROOTPAGENAME}}|{{PAGENAME}}|[[Special:Edit/{{FULLPAGENAME}}|Post a message to ''{{#invoke:String|replace|source={{PAGENAME}}|­}}]]''|[[Special:Edit/{{FULLPAGENAME}}|Start the ''{{#invoke:String|replace|source={{FULLPAGENAME}}|­}}'' page]] or [[Special:NewSection/{{FULLPAGENAME}}|leave a message about the ''{{#invoke:String|replace|source={{SUBJECTPAGENAME}}|­}}]]''}} | {{ns:5}} | {{ns:7}} | {{ns:9}} | {{ns:11}} | {{ns:13}} | {{ns:15}} | {{ns:101}} | {{ns:119}} | {{ns:711}} | {{ns:829}} | {{ns:1}} = [[Special:Edit/{{FULLPAGENAME}}|Start the ''{{#invoke:String|replace|source={{FULLPAGENAME}}|­}}'' page]] or [[Special:NewSection/{{FULLPAGENAME}}|leave a message about the ''{{#invoke:String|replace|source={{SUBJECTPAGENAME}}|­}}]]'' | {{ns:Category}} = [[Special:Edit/{{FULLPAGENAME}}|Start the ''{{#invoke:String|replace|source={{FULLPAGENAME}}|}}'']] | {{ns:Project}} = [[Special:Edit/{{FULLPAGENAME}}|Start the ''{{#invoke:String|replace|source={{FULLPAGENAME}}|­}}'' page]] or [[Special:NewSection/{{FULLPAGENAME}}|start a discussion about the ''{{#invoke:String|replace|source={{FULLPAGENAME}}|­}}]]'' | #default = [[Special:Edit/{{FULLPAGENAME}}|Start the ''{{#invoke:String|replace|source={{FULLPAGENAME}}|}}'' page]] }}''' {{ #if: {{NAMESPACE}} |by using the '''"[[Wikipedia:Namespaces|{{NAMESPACE}}]]"''' namespace|by using the '''"[[Wikipedia:Namespaces|Page]]"''' namespace, using the [[Wikipedia:Article wizard|Article Wizard]] if you want to create it & submit it for review, or [[{{ns:Project}}:Requested articles|add a request for the new page]] }}.}} }}{{ #switch: {{NAMESPACE}} | {{ns:0}} = * {{plain link|url=https://test.wikipedia.org/w/index.php?search={{urlencode:{{#titleparts:{{#invoke:String|replace|source={{PAGENAME}}|­}}}}}}&title=Special%3ASearch&fulltext=1&ns{{NAMESPACENUMBER}}=1|name=Search for "''{{#invoke:String|replace|source={{PAGENAME}}|­}}''"}} in existing pages. * [[wiktionary:en:Special:Search/{{FULLPAGENAME}}|Look for "{{FULLPAGENAME}}"]] in Wiktionary, our sister dictionary project. * [[commons:Special:Search/{{FULLPAGENAME}}|Look for "{{FULLPAGENAME}}"]] in the Wikimedia Commons, our repository for free images, music, sound, and video. | {{ns:User}} = * [[{{ns:Special}}:WhatLinksHere/{{#invoke:String|replace|source={{FULLPAGENAME}}|­}}|Look for pages within the Test Wikipedia that link to this user page]]. | {{ns:User talk}} = * [[{{ns:Special}}:WhatLinksHere/{{#invoke:String|replace|source={{FULLPAGENAME}}|­}}|Look for pages within the Test Wikipedia that link to this user talk page]]. | {{ns:Category}} = * {{plain link|url=https://test.wikipedia.org/w/index.php?search={{urlencode:{{#titleparts:{{#invoke:String|replace|source={{PAGENAME}}|­}}}}}}&title=Special%3ASearch&fulltext=1&ns{{NAMESPACENUMBER}}=1|name=Search for "''{{#invoke:String|replace|source={{PAGENAME}}|­}}''"}} in existing categories. * [[wiktionary:en:Special:Search/{{FULLPAGENAME}}|Look for "{{FULLPAGENAME}}"]] in Wiktionary, our sister dictionary project. * [[commons:Special:Search/{{FULLPAGENAME}}|Look for "{{FULLPAGENAME}}"]] in the Wikimedia Commons, our repository for free images, music, sound, and video. | {{ns:File}} = * {{plain link|url=https://test.wikipedia.org/w/index.php?search={{urlencode:{{#titleparts:{{#invoke:String|replace|source={{PAGENAME}}|­}}}}}}&title=Special%3ASearch&fulltext=1&ns{{NAMESPACENUMBER}}=1|name=Search for "''{{#invoke:String|replace|source={{PAGENAME}}|­}}''"}} in existing files. * [[commons:Special:Search/{{FULLPAGENAME}}|Look for "{{FULLPAGENAME}}"]] in the Wikimedia Commons, our repository for free images, music, sound, and video. | {{ns:Template}} = * {{plain link|url=https://test.wikipedia.org/w/index.php?search={{urlencode:{{#titleparts:{{#invoke:String|replace|source={{PAGENAME}}|­}}}}}}&title=Special%3ASearch&fulltext=1&ns{{NAMESPACENUMBER}}=1|name=Search for "''{{#invoke:String|replace|source={{PAGENAME}}|­}}''"}} in existing templates. * [[wikimedia:Special:Search/{{FULLPAGENAME}}|Look for "{{FULLPAGENAME}}"]] in Wikimedia, the Free Templates, Categories, & More! | #default = * {{plain link|url=https://test.wikipedia.org/w/index.php?search={{urlencode:{{#titleparts:{{#invoke:String|replace|source={{PAGENAME}}|­}}}}}}&title=Special%3ASearch&fulltext=1&ns{{NAMESPACENUMBER}}=1|name=Search for "''{{#invoke:String|replace|source={{PAGENAME}}|­}}''"}} in existing {{#if: {{NAMESPACE}} | pages with the '''"[[{{ns:Project}}:Namespaces|{{NAMESPACE}}]]"''' namespace | pages without using [[{{ns:Project}}:Namespaces|namespaces]] }}. * [[{{ns:Special}}:WhatLinksHere/{{#invoke:String|replace|source={{FULLPAGENAME}}|­}}|Look for pages within the Test Wikipedia that link to this title]]. }} * {{ #ifeq: {{NAMESPACE}} | {{TALKSPACE}} | You can go back to your [[:{{SUBJECTPAGENAME}}|subject page]] | Please discuss changes on your [[{{TALKPAGENAME}}|talk page]] }}. <div id="noarticletext_technical"> ---- '''Other reasons that may be displayed this message:''' * If {{ #ifeq: {{NAMESPACE}} | {{ns:File}} | a file | a page }} was recently edited here, it may be invisible. (Because of a delay in updating the database.) You can wait a few minutes to complete, you can [[Special:Purge/{{FULLPAGENAME}}|click it]] for purging, or you may want to [[Special:Protect/{{FULLPAGENAME}}|protect]] this page. You can also want to [[Special:Edit/{{FULLPAGENAME}}|edit this page]] or [[Special:Delete/{{FULLPAGENAME}}|delete this page]]. * Titles on the Test Wikipedia is in the '''[[w:en:Case sensitivity|case sensitivity]]''' except for this first character; please {{plain link|url=https://test.wikipedia.org/w/index.php?search={{urlencode:{{#titleparts:{{#invoke:String|replace|source={{FULLPAGENAME}}|­}}}}}}&title=Special%3ASearch&fulltext=1|name=check the Test Wikipedia's alternative capitalizations}} and consider adding some [[Wikipedia:Redirects|redirects]] here to the correct title. If the page you are looking for is not TestSite, see its corresponding [[w:en:Main Page|language Wikipedia]]. If the page is not a [[w:en:test wiki|test wiki]], check one of the [[wikimedia:Main Page|other Foundation wikis]]. * If this page has been deleted, try [{{fullurl:Special:Log/delete|page={{#invoke:String|replace|source={{FULLPAGENAMEE}}|­}}}} checking the '''deletion log'''], and see [[Wikipedia:Why was the page I created deleted?|the Why was the page I created deleted?]] for possible reasons. </div> }} <!--End fmbox --><!--Start book box-->{{#if:{{#invoke:String|match|{{FULLPAGENAME}}|^Book:|nomatch= }}{{#invoke:String|match|{{FULLPAGENAME}}|^Book talk:|nomatch= }}|{{fmbox|type=system|text=<strong>This page may have existed as part of the former book & talk namespace.</strong> If so it was likely moved to [[{{#invoke:String|replace|{{#invoke:String|replace|{{FULLPAGENAME}}|^Book talk:|Book:|plain=False}}|^Book:|Wikipedia:Books/archive/|plain=False}}]] before being deleted. See [[Wikipedia:Books]] for more information.}}}}<!--End book box--> </div> == {{ #switch: {{NAMESPACE}} | {{ns:0}} = Page | {{ns:Talk}} = [[{{ns:Help}}:Using talk pages|Discussion page]] | {{TALKSPACE}} = [[{{ns:Help}}:Using talk pages|{{SUBJECTSPACE}}'s Discussion page]] | {{ns:Category}} = [[{{ns:Project}}:Categorization|Category]] | {{ns:Help}} = [[{{ns:Help}}:Contents|Help page]] | {{ns:File}} = [[{{ns:Project}}:Files to upload|File]] | {{ns:Portal}} = [[{{ns:Project}}:Portal|Portal]] | {{ns:Template}} = [[{{ns:Project}}:Template messages|Template]] | {{ns:User}} = [[{{ns:Project}}:User pages|User page]] | {{ns:Project}} = [[{{ns:Project}}:Project namespace|Project page]] | {{ns:MediaWiki}} = [[Special:AllMessages|System message]] | #default = {{NAMESPACE}} page}} not showing up? == Reload the page you just created "'''{{FULLPAGENAME}}'''." <small>You may also [[Wikipedia:Administrators' noticeboard|contact an administrator]] before recreating this page.</small> If you can't find the page, you can [[Special:Search/{{FULLPAGENAME}}|search for an existing page]] or [[Special:Edit/{{FULLPAGENAME}}|create it]]. {{ #ifeq: {{{nopermission}}} | yes |{{fmbox | type = warning | id = noarticletext | image = none | text = You do not have permission to create this page. It may have been {{#if {{PROTECTIONLEVEL:create}} | protected | restricted }} from creation. <span class="user-show">If I think this page should be created here, please unprotect this page at [[Wikipedia:Administrators' noticeboard|the Administrators' noticeboard]].</span>.}}|{{fmbox | type = system | id = noarticletext | image = none | text = If you can't find {{FULLPAGENAME}}, you can also include the <span class="planlinks">[{{fullurl:{{FULLPAGENAME}}|veaction=edit}} visual editor]</span>, {{ #ifeq: {{NAMESPACE}} | {{TALKSPACE}} | the <span class="planlinks">[{{fullurl:{{FULLPAGENAME}}|action=edit&veswitched=1}} source editor]</span>, or [[Special:NewSection/{{FULLPAGENAME}}|create a new section]] | or the <span class="planlinks">[{{fullurl:{{FULLPAGENAME}}|action=edit&veswitched=1}} source editor]</span> }} for editing.}}}} <noinclude> {{documentation}} </noinclude> owe9zf895ydvai4oirdergbsitgqrdr 739054 739046 2026-04-22T00:15:21Z Sheffalump 71152 739054 wikitext text/x-wiki <div class="mw-parser-output"><!-- don't touch this div to the left, it makes TemplateStyles vroom vroom --> {{New page DYM}} {{ #ifeq: {{NAMESPACE}} | {{TALKSPACE}} |{{#ifexist: {{SUBJECTPAGENAME}}|This is the talk page for [[:{{SUBJECTPAGENAME}}]].|[[:{{SUBJECTPAGENAME}}]] has not yet been created. {{Viewing talk page without subject}}|}}}} {{fmbox | type = system | id = noarticletext | image = none | textstyle = padding: 0.6em 0.9em; <!--Large box needs more padding--> | text = {{#tag:strong|WARNING:}} {{ #ifeq: {{ #ifeq: {{FULLPAGENAME}} | Template:No article text || }} | <!--Mainspace sister project infobox--> | {{No article text/sister projects}} }}{{ #ifeq: {{NAMESPACE}} | {{ns:User talk}} | {{#tag:strong|No messages}} have been posted for {{BASEPAGENAME}} yet. | {{#tag:strong|Wikipedia does not contain {{ #switch: {{NAMESPACE}} | {{ns:0}} = a {{#tag:em|[[{{ns:Project}}:Using pages without namespaces|page]]}} | {{ns:Talk}} = a {{#tag:em|[[{{ns:Help}}:Using talk pages|discussion page]]}} | {{TALKSPACE}} = the {{#tag:em|[[{{ns:Help}}:Using talk pages|{{SUBJECTSPACE}}'s discussion page]]}} | {{ns:Category}} = a {{#tag:em|[[{{ns:Project}}:Categorization|category]]}} | {{ns:Help}} = a {{#tag:em|[[{{ns:Help}}:Contents|help page]]}} | {{ns:File}} = a {{#tag:em|[[{{ns:Project}}:Files to upload|file]]}} | {{ns:Portal}} = a {{#tag:em|[[{{ns:Project}}:Portal|portal]]}} | {{ns:Template}} = a {{#tag:em|[[{{ns:Project}}:Template messages|template]]}} | {{ns:User}} = a {{#tag:em|[[{{ns:Project}}:User pages|user page]]}} | {{ns:Project}} = a {{#tag:em|[[{{ns:Project}}:Project namespace|project page]]}} | {{ns:MediaWiki}} = a {{#tag:em|[[Special:AllMessages|system message]]}} | #default = a {{#tag:em|[[{{ns:Project}}:Namespaces|{{NAMESPACE}} page]]}} }} with this exact name yet.}} {{ #ifeq: {{#invoke:String|replace|source={{PAGENAME}}|­}} | {{#invoke:String|replace|source={{SUBPAGENAME}}|­}} | {{ #switch: {{NAMESPACE}} | {{ns:0}} = Please {{plain link|url=https://test.wikipedia.org/w/index.php?search={{urlencode:{{#titleparts:{{#invoke:String|replace|source={{PAGENAME}}|­}}}}}}&title=Special%3ASearch&fulltext=1|name=search for ''{{#invoke:String|replace|source={{PAGENAME}}|­}}'' in Test Wikipedia}} to check for alternative titles, names, or spellings. | {{ns:Talk}} = Before creating this page, please verify that a page called [[{{PAGENAME}}]] exists. | {{TALKSPACE}} = Before creating this page, please verify that [[:{{SUBJECTPAGENAME}}]] is already made. | {{ns:Category}} = Please browse the [[Portal:Contents|existing categories]] to check if this category is covered under another name. | {{ns:Help}} = Please browse the [[{{ns:Help}}:Contents|existing help pages]] to check if this help topic is covered under another name. | {{ns:File}} = Please do not manually create this page. If you want to upload ''File:{{PAGENAME}}'', Please see the [[{{ns:Project}}:Files to upload|Files to upload]] for instructions & tutorials. | {{ns:Portal}} = Please browse the [[{{ns:Portal}}:Contents/Portals|existing portals]] to check for similar topics. | {{ns:Template}} = Please browse the [[{{ns:Project}}:Template messages|existing templates]] to check if this standardized message is available under another name. | {{ns:User}} = In general, this page should be created and edited by [[User:{{PAGENAME}}]]. If you're already registered, Please [[Special:UserLogin|log in]]. If you don't have an account, [[Special:CreateAccount|create one]]. If you are {{PAGENAME}}, click [[Special:Edit/User:{{PAGENAME}}|create this page]]. If you are not {{PAGENAME}}, don't click "create this page". | {{ns:Project}} = Please browse the [[{{ns:Project}}:List of policies and guidelines|existing policies and guidelines]] or [[Special:Search/{{ns:Project}}:{{PAGENAME}}|search]] for similar existing project pages. | {{ns:MediaWiki}} = Please browse the [[Special:AllMessages|existing system messages]] to check if this Non-CSS, Non-JavaScript, Non-JSON, CSS, JavaScript, & JSON pages are available under another name. | #default = Please browse the [[{{ns:Project}}:Namespaces|existing {{NAMESPACE}} pages]] to check if this {{NAMESPACE}} namespace is available under another name. }} | {{ #ifeq: {{{nopermission}}} | yes |You do not have permission to edit pages in the {{#if: {{NAMESPACE}} | '''[[Wikipedia:Namespaces|{{NAMESPACE}}]]''' namespace | '''[[Wikipedia:Namespaces|Page]]''' namespace }}. Please [{{fullurl:Special:UserLogin|returnto={{ urlencode: {{#invoke:String|replace|source={{FULLPAGENAME}}|­}} }}}} log in] or [{{fullurl:Special:UserLogin/signup|returnto={{ urlencode: {{#invoke:String|replace|source={{FULLPAGENAME}}|­}} }}}} sign up] if you want to create this page. (This page is currently protected so only administrators, system administrators, template editors, extended confirmed users, page movers, autoconfirmed users, & logged in users can make it, '''not''' temporary accounts or unregistered (IP) users). (If you're logged out, {{SITENAME}} has restricted the ability to create new pages. You can go back and edit an existing page, or [[Special:UserLogin|log in or create an account]]. If you're logged in, You do not have permission to create new pages.) Please see [[{{ns:Project}}:Subpages|Subpages]] for subpages if you do not create it because this isn't needed. To protect the page, click [[Special:Protect/{{FULLPAGENAME}}|protect]].| Before creating this page in the {{#if: {{NAMESPACE}} | '''[[Wikipedia:Namespaces|{{NAMESPACE}}]]''' namespace | '''[[Wikipedia:Namespaces|Page]]''' namespace }}, please see [[{{ns:Project}}:Subpages|Subpages]] for subpages. To protect the page, click [[Special:Protect/{{FULLPAGENAME}}|protect]].}} }} }}{{ #ifeq: {{{nopermission}}} | yes |* {{ #switch: {{#invoke:Effective protection level|create|{{#invoke:String|replace|source={{FULLPAGENAME}}|­}}}} | sysop = Administrators can't edit this {{NAMESPACE}} page, but still be able to edit pages by autoconfirmed users, users, anonymous users, & temporally accounts. You will <span class="anononly">need to [{{fullurl:Special:UserLogin|returnto={{ urlencode: {{#invoke:String|replace|source={{FULLPAGENAME}}|­}} }}}} log in or create an account] and will</span> be [[Wikipedia:Administrators|administrators]] to create new pages, system messages, & JSON pages. | interfaceadmin = System administrators can't edit this {{NAMESPACE}} page, but still be able to edit pages by autoconfirmed users, users, anonymous users, & temporally accounts. You will <span class="anononly">need to [{{fullurl:Special:UserLogin|returnto={{ urlencode: {{#invoke:String|replace|source={{FULLPAGENAME}}|­}} }}}} log in or create an account] and will </span>be [[Wikipedia:System administrators|system administrators]] to create new CSS & JavaScript pages. | templateeditor = Template editors & administrators can't edit this {{NAMESPACE}} page, but still be able to edit pages by autoconfirmed users, users, anonymous users, & temporally accounts. You will <span class="anononly">need to [{{fullurl:Special:UserLogin|returnto={{ urlencode: {{#invoke:String|replace|source={{FULLPAGENAME}}|­}} }}}} log in or create an account] and will</span> be [[WP:Template editor|template editors]] to create new pages. | extendedconfirmed = Extended confirmed users & administrators can't edit this {{NAMESPACE}} page, but still be able to edit pages by autoconfirmed users, users, anonymous users, & temporally accounts. You will <span class="anononly">need to [{{fullurl:Special:UserLogin|returnto={{ urlencode: {{#invoke:String|replace|source={{FULLPAGENAME}}|­}} }}}} log in or create an account] and will</span> be [[Wikipedia:User access levels#Extendedconfirmed|extended confirmed users]] to create new pages. | autoconfirmed = Autoconfirmed users can't edit this {{NAMESPACE}} page, but still be able to edit pages by users, anonymous users, & temporally accounts. You will <span class="anononly">need to [{{fullurl:Special:UserLogin|returnto={{ urlencode: {{#invoke:String|replace|source={{FULLPAGENAME}}|­}} }}}} log in or create an account] and will </span>be [[WP:User access levels#Autoconfirmed users|autoconfirmed users]] to create new pages. (After 4 days & 10 edits on English Wikipedia.) | user = Some users can't edit this {{NAMESPACE}} page, but still be able to edit pages by anonymous users & temporally accounts. You will need to [{{fullurl:Special:UserLogin|returnto={{ urlencode: {{#invoke:String|replace|source={{FULLPAGENAME}}|­}} }}}} log in or create an account] to make this page. {{#ifeq:{{NAMESPACE}}|{{ns:Category}}|Or, you can [[Wikipedia:Articles for creation/Categories|request the creation of a new category]].}} | #default = Users with the "Create" permission can't edit this {{NAMESPACE}} page. (You do not have permission to create this page when not logged in). You will need to [{{fullurl:Special:UserLogin|returnto={{ urlencode: {{#invoke:String|replace|source={{FULLPAGENAME}}|­}} }}}} log in or create an account] and will be [[WP:User access levels#Autoconfirmed users|autoconfirmed users]] to make your own page. }} |{{#ifeq:{{#invoke:Title blacklist|main|action=create|pagename={{#invoke:String|replace|source={{FULLPAGENAME}}|­}}}}|templateeditor|* Administrators, template editors, & page movers can't edit this {{NAMESPACE}} page, but still be able to edit pages by autoconfirmed users, users, anonymous users, & temporally accounts. You will need to [{{fullurl:Special:UserLogin|returnto={{ urlencode: {{#invoke:String|replace|source={{FULLPAGENAME}}|­}} }}}} log in or create an account] and will be [[Wikipedia:Administrators|administrators]], [[Wikipedia:Template editors|template editors]], & [[Wikipedia:Page movers|page movers]] to create new ones.|* ''' {{ #switch: {{NAMESPACE}} | {{ns:3}} = {{#ifeq:{{ROOTPAGENAME}}|{{PAGENAME}}|[[Special:Edit/{{FULLPAGENAME}}|Post a message to ''{{#invoke:String|replace|source={{PAGENAME}}|­}}]]''|[[Special:Edit/{{FULLPAGENAME}}|Start the ''{{#invoke:String|replace|source={{FULLPAGENAME}}|­}}'' page]] or [[Special:NewSection/{{FULLPAGENAME}}|leave a message about the ''{{#invoke:String|replace|source={{SUBJECTPAGENAME}}|­}}]]''}} | {{ns:5}} | {{ns:7}} | {{ns:9}} | {{ns:11}} | {{ns:13}} | {{ns:15}} | {{ns:101}} | {{ns:119}} | {{ns:711}} | {{ns:829}} | {{ns:1}} = [[Special:Edit/{{FULLPAGENAME}}|Start the ''{{#invoke:String|replace|source={{FULLPAGENAME}}|­}}'' page]] or [[Special:NewSection/{{FULLPAGENAME}}|leave a message about the ''{{#invoke:String|replace|source={{SUBJECTPAGENAME}}|­}}]]'' | {{ns:Category}} = [[Special:Edit/{{FULLPAGENAME}}|Start the ''{{#invoke:String|replace|source={{FULLPAGENAME}}|}}'']] | {{ns:Project}} = [[Special:Edit/{{FULLPAGENAME}}|Start the ''{{#invoke:String|replace|source={{FULLPAGENAME}}|­}}'' page]] or [[Special:NewSection/{{FULLPAGENAME}}|start a discussion about the ''{{#invoke:String|replace|source={{FULLPAGENAME}}|­}}]]'' | #default = [[Special:Edit/{{FULLPAGENAME}}|Start the ''{{#invoke:String|replace|source={{FULLPAGENAME}}|}}'' page]] }}''' {{ #if: {{NAMESPACE}} |by using the '''"[[Wikipedia:Namespaces|{{NAMESPACE}}]]"''' namespace|by using the '''"[[Wikipedia:Namespaces|Page]]"''' namespace, using the [[Wikipedia:Article wizard|Article Wizard]] if you want to create it & submit it for review, or [[{{ns:Project}}:Requested articles|add a request for the new page]] }}.}} }}{{ #switch: {{NAMESPACE}} | {{ns:0}} = * {{plain link|url=https://test.wikipedia.org/w/index.php?search={{urlencode:{{#titleparts:{{#invoke:String|replace|source={{PAGENAME}}|­}}}}}}&title=Special%3ASearch&fulltext=1&ns{{NAMESPACENUMBER}}=1|name=Search for "''{{#invoke:String|replace|source={{PAGENAME}}|­}}''"}} in existing pages. * [[wiktionary:en:Special:Search/{{FULLPAGENAME}}|Look for "{{FULLPAGENAME}}"]] in Wiktionary, our sister dictionary project. * [[commons:Special:Search/{{FULLPAGENAME}}|Look for "{{FULLPAGENAME}}"]] in the Wikimedia Commons, our repository for free images, music, sound, and video. | {{ns:User}} = * [[{{ns:Special}}:WhatLinksHere/{{#invoke:String|replace|source={{FULLPAGENAME}}|­}}|Look for pages within the Test Wikipedia that link to this user page]]. | {{ns:User talk}} = * [[{{ns:Special}}:WhatLinksHere/{{#invoke:String|replace|source={{FULLPAGENAME}}|­}}|Look for pages within the Test Wikipedia that link to this user talk page]]. | {{ns:Category}} = * {{plain link|url=https://test.wikipedia.org/w/index.php?search={{urlencode:{{#titleparts:{{#invoke:String|replace|source={{PAGENAME}}|­}}}}}}&title=Special%3ASearch&fulltext=1&ns{{NAMESPACENUMBER}}=1|name=Search for "''{{#invoke:String|replace|source={{PAGENAME}}|­}}''"}} in existing categories. * [[wiktionary:en:Special:Search/{{FULLPAGENAME}}|Look for "{{FULLPAGENAME}}"]] in Wiktionary, our sister dictionary project. * [[commons:Special:Search/{{FULLPAGENAME}}|Look for "{{FULLPAGENAME}}"]] in the Wikimedia Commons, our repository for free images, music, sound, and video. | {{ns:File}} = * {{plain link|url=https://test.wikipedia.org/w/index.php?search={{urlencode:{{#titleparts:{{#invoke:String|replace|source={{PAGENAME}}|­}}}}}}&title=Special%3ASearch&fulltext=1&ns{{NAMESPACENUMBER}}=1|name=Search for "''{{#invoke:String|replace|source={{PAGENAME}}|­}}''"}} in existing files. * [[commons:Special:Search/{{FULLPAGENAME}}|Look for "{{FULLPAGENAME}}"]] in the Wikimedia Commons, our repository for free images, music, sound, and video. | {{ns:Template}} = * {{plain link|url=https://test.wikipedia.org/w/index.php?search={{urlencode:{{#titleparts:{{#invoke:String|replace|source={{PAGENAME}}|­}}}}}}&title=Special%3ASearch&fulltext=1&ns{{NAMESPACENUMBER}}=1|name=Search for "''{{#invoke:String|replace|source={{PAGENAME}}|­}}''"}} in existing templates. * [[wikimedia:Special:Search/{{FULLPAGENAME}}|Look for "{{FULLPAGENAME}}"]] in Wikimedia, the Free Templates, Categories, & More! | #default = * {{plain link|url=https://test.wikipedia.org/w/index.php?search={{urlencode:{{#titleparts:{{#invoke:String|replace|source={{PAGENAME}}|­}}}}}}&title=Special%3ASearch&fulltext=1&ns{{NAMESPACENUMBER}}=1|name=Search for "''{{#invoke:String|replace|source={{PAGENAME}}|­}}''"}} in existing {{#if: {{NAMESPACE}} | pages with the '''"[[{{ns:Project}}:Namespaces|{{NAMESPACE}}]]"''' namespace | pages without using [[{{ns:Project}}:Namespaces|namespaces]] }}. * [[{{ns:Special}}:WhatLinksHere/{{#invoke:String|replace|source={{FULLPAGENAME}}|­}}|Look for pages within the Test Wikipedia that link to this title]]. }} * {{ #ifeq: {{NAMESPACE}} | {{TALKSPACE}} | You can go back to your [[:{{SUBJECTPAGENAME}}|subject page]] | Please discuss changes on your [[{{TALKPAGENAME}}|talk page]] }}. <div id="noarticletext_technical"> ---- '''Other reasons that may be displayed this message:''' * If {{ #ifeq: {{NAMESPACE}} | {{ns:File}} | a file | a page }} was recently edited here, it may be invisible. (Because of a delay in updating the database.) You can wait a few minutes to complete, you can [[Special:Purge/{{FULLPAGENAME}}|click it]] for purging, or you may want to [[Special:Protect/{{FULLPAGENAME}}|protect]] this page. You can also want to [[Special:Edit/{{FULLPAGENAME}}|edit this page]] or [[Special:Delete/{{FULLPAGENAME}}|delete this page]]. * Titles on the Test Wikipedia is in the '''[[w:en:Case sensitivity|case sensitivity]]''' except for this first character; please {{plain link|url=https://test.wikipedia.org/w/index.php?search={{urlencode:{{#titleparts:{{#invoke:String|replace|source={{FULLPAGENAME}}|­}}}}}}&title=Special%3ASearch&fulltext=1|name=check the Test Wikipedia's alternative capitalizations}} and consider adding some [[Wikipedia:Redirects|redirects]] here to the correct title. If the page you are looking for is not TestSite, see its corresponding [[w:en:Main Page|language Wikipedia]]. If the page is not a [[w:en:test wiki|test wiki]], check one of the [[wikimedia:Main Page|other Foundation wikis]]. * If this page has been deleted, try [{{fullurl:Special:Log/delete|page={{#invoke:String|replace|source={{FULLPAGENAMEE}}|­}}}} checking the '''deletion log'''], and see [[Wikipedia:Why was the page I created deleted?|the Why was the page I created deleted?]] for possible reasons. </div> }} <!--End fmbox --><!--Start book box-->{{#if:{{#invoke:String|match|{{FULLPAGENAME}}|^Book:|nomatch= }}{{#invoke:String|match|{{FULLPAGENAME}}|^Book talk:|nomatch= }}|{{fmbox|type=system|text=<strong>This page may have existed as part of the former book & talk namespace.</strong> If so it was likely moved to [[{{#invoke:String|replace|{{#invoke:String|replace|{{FULLPAGENAME}}|^Book talk:|Book:|plain=False}}|^Book:|Wikipedia:Books/archive/|plain=False}}]] before being deleted. See [[Wikipedia:Books]] for more information.}}}}<!--End book box--> </div> == {{ #switch: {{NAMESPACE}} | {{ns:0}} = Page | {{ns:Talk}} = [[{{ns:Help}}:Using talk pages|Discussion page]] | {{TALKSPACE}} = [[{{ns:Help}}:Using talk pages|{{SUBJECTSPACE}}'s Discussion page]] | {{ns:Category}} = [[{{ns:Project}}:Categorization|Category]] | {{ns:Help}} = [[{{ns:Help}}:Contents|Help page]] | {{ns:File}} = [[{{ns:Project}}:Files to upload|File]] | {{ns:Portal}} = [[{{ns:Project}}:Portal|Portal]] | {{ns:Template}} = [[{{ns:Project}}:Template messages|Template]] | {{ns:User}} = [[{{ns:Project}}:User pages|User page]] | {{ns:Project}} = [[{{ns:Project}}:Project namespace|Project page]] | {{ns:MediaWiki}} = [[Special:AllMessages|System message]] | #default = {{NAMESPACE}} page}} not showing up? == Reload the page you just created "'''{{FULLPAGENAME}}'''." <small>You may also [[Wikipedia:Administrators' noticeboard|contact an administrator]] before recreating this page.</small> If you can't find the page, you can [[Special:Search/{{FULLPAGENAME}}|search for an existing page]] or [[Special:Edit/{{FULLPAGENAME}}|create it]]. {{ #ifeq: {{{nopermission}}} | yes |<div class="mw-parser-output">{{fmbox | type = warning | id = noarticletext | image = none | text = You do not have permission to create this page. It may have been protected from creation. If I think this page should be created here, please unprotect this page at [[Wikipedia:Administrators' noticeboard|the Administrators' noticeboard]].}}</div>|<div class="mw-parser-output">{{fmbox | type = system | id = noarticletext | image = none | text = If you can't find {{FULLPAGENAME}}, you can also include the <span class="planlinks">[{{fullurl:{{FULLPAGENAME}}|veaction=edit}} visual editor]</span>, {{ #ifeq: {{NAMESPACE}} | {{TALKSPACE}} | the <span class="planlinks">[{{fullurl:{{FULLPAGENAME}}|action=edit&veswitched=1}} source editor]</span>, or [[Special:NewSection/{{FULLPAGENAME}}|create a new section]] | or the <span class="planlinks">[{{fullurl:{{FULLPAGENAME}}|action=edit&veswitched=1}} source editor]</span> }} for editing.}}</div>}} <noinclude> {{documentation}} </noinclude> 4t261j5qsz391mp2d93wjpatb6nuarp 739056 739054 2026-04-22T00:20:28Z Sheffalump 71152 739056 wikitext text/x-wiki <div class="mw-parser-output"><!-- don't touch this div to the left, it makes TemplateStyles vroom vroom --> {{New page DYM}} {{ #ifeq: {{NAMESPACE}} | {{TALKSPACE}} |{{#ifexist: {{SUBJECTPAGENAME}}|This is the talk page for [[:{{SUBJECTPAGENAME}}]].|[[:{{SUBJECTPAGENAME}}]] has not yet been created. {{Viewing talk page without subject}}|}}}} {{fmbox | type = system | id = noarticletext | image = none | textstyle = padding: 0.6em 0.9em; <!--Large box needs more padding--> | text = {{#tag:strong|WARNING:}} {{ #ifeq: {{ #ifeq: {{FULLPAGENAME}} | Template:No article text || }} | <!--Mainspace sister project infobox--> | {{No article text/sister projects}} }}{{ #ifeq: {{NAMESPACE}} | {{ns:User talk}} | {{#tag:strong|No messages}} have been posted for {{BASEPAGENAME}} yet. | {{#tag:strong|Wikipedia does not contain {{ #switch: {{NAMESPACE}} | {{ns:0}} = a {{#tag:em|[[{{ns:Project}}:Using pages without namespaces|page]]}} | {{ns:Talk}} = a {{#tag:em|[[{{ns:Help}}:Using talk pages|discussion page]]}} | {{TALKSPACE}} = the {{#tag:em|[[{{ns:Help}}:Using talk pages|{{SUBJECTSPACE}}'s discussion page]]}} | {{ns:Category}} = a {{#tag:em|[[{{ns:Project}}:Categorization|category]]}} | {{ns:Help}} = a {{#tag:em|[[{{ns:Help}}:Contents|help page]]}} | {{ns:File}} = a {{#tag:em|[[{{ns:Project}}:Files to upload|file]]}} | {{ns:Portal}} = a {{#tag:em|[[{{ns:Project}}:Portal|portal]]}} | {{ns:Template}} = a {{#tag:em|[[{{ns:Project}}:Template messages|template]]}} | {{ns:User}} = a {{#tag:em|[[{{ns:Project}}:User pages|user page]]}} | {{ns:Project}} = a {{#tag:em|[[{{ns:Project}}:Project namespace|project page]]}} | {{ns:MediaWiki}} = a {{#tag:em|[[Special:AllMessages|system message]]}} | #default = a {{#tag:em|[[{{ns:Project}}:Namespaces|{{NAMESPACE}} page]]}} }} with this exact name yet.}} {{ #ifeq: {{#invoke:String|replace|source={{PAGENAME}}|­}} | {{#invoke:String|replace|source={{SUBPAGENAME}}|­}} | {{ #switch: {{NAMESPACE}} | {{ns:0}} = Please {{plain link|url=https://test.wikipedia.org/w/index.php?search={{urlencode:{{#titleparts:{{#invoke:String|replace|source={{PAGENAME}}|­}}}}}}&title=Special%3ASearch&fulltext=1|name=search for ''{{#invoke:String|replace|source={{PAGENAME}}|­}}'' in Test Wikipedia}} to check for alternative titles, names, or spellings. | {{ns:Talk}} = Before creating this page, please verify that a page called [[{{PAGENAME}}]] exists. | {{TALKSPACE}} = Before creating this page, please verify that [[:{{SUBJECTPAGENAME}}]] is already made. | {{ns:Category}} = Please browse the [[Portal:Contents|existing categories]] to check if this category is covered under another name. | {{ns:Help}} = Please browse the [[{{ns:Help}}:Contents|existing help pages]] to check if this help topic is covered under another name. | {{ns:File}} = Please do not manually create this page. If you want to upload ''File:{{PAGENAME}}'', Please see the [[{{ns:Project}}:Files to upload|Files to upload]] for instructions & tutorials. | {{ns:Portal}} = Please browse the [[{{ns:Portal}}:Contents/Portals|existing portals]] to check for similar topics. | {{ns:Template}} = Please browse the [[{{ns:Project}}:Template messages|existing templates]] to check if this standardized message is available under another name. | {{ns:User}} = In general, this page should be created and edited by [[User:{{PAGENAME}}]]. If you're already registered, Please [[Special:UserLogin|log in]]. If you don't have an account, [[Special:CreateAccount|create one]]. If you are {{PAGENAME}}, click [[Special:Edit/User:{{PAGENAME}}|create this page]]. If you are not {{PAGENAME}}, don't click "create this page". | {{ns:Project}} = Please browse the [[{{ns:Project}}:List of policies and guidelines|existing policies and guidelines]] or [[Special:Search/{{ns:Project}}:{{PAGENAME}}|search]] for similar existing project pages. | {{ns:MediaWiki}} = Please browse the [[Special:AllMessages|existing system messages]] to check if this Non-CSS, Non-JavaScript, Non-JSON, CSS, JavaScript, & JSON pages are available under another name. | #default = Please browse the [[{{ns:Project}}:Namespaces|existing {{NAMESPACE}} pages]] to check if this {{NAMESPACE}} namespace is available under another name. }} | {{ #ifeq: {{{nopermission}}} | yes |You do not have permission to edit pages in the {{#if: {{NAMESPACE}} | '''[[Wikipedia:Namespaces|{{NAMESPACE}}]]''' namespace | '''[[Wikipedia:Namespaces|Page]]''' namespace }}. Please [{{fullurl:Special:UserLogin|returnto={{ urlencode: {{#invoke:String|replace|source={{FULLPAGENAME}}|­}} }}}} log in] or [{{fullurl:Special:UserLogin/signup|returnto={{ urlencode: {{#invoke:String|replace|source={{FULLPAGENAME}}|­}} }}}} sign up] if you want to create this page. (This page is currently protected so only administrators, system administrators, template editors, extended confirmed users, page movers, autoconfirmed users, & logged in users can make it, '''not''' temporary accounts or unregistered (IP) users). (If you're logged out, {{SITENAME}} has restricted the ability to create new pages. You can go back and edit an existing page, or [[Special:UserLogin|log in or create an account]]. If you're logged in, You do not have permission to create new pages.) Please see [[{{ns:Project}}:Subpages|Subpages]] for subpages if you do not create it because this isn't needed. To protect the page, click [[Special:Protect/{{FULLPAGENAME}}|protect]].| Before creating this page in the {{#if: {{NAMESPACE}} | '''[[Wikipedia:Namespaces|{{NAMESPACE}}]]''' namespace | '''[[Wikipedia:Namespaces|Page]]''' namespace }}, please see [[{{ns:Project}}:Subpages|Subpages]] for subpages. To protect the page, click [[Special:Protect/{{FULLPAGENAME}}|protect]].}} }} }}{{ #ifeq: {{{nopermission}}} | yes |* {{ #switch: {{#invoke:Effective protection level|create|{{#invoke:String|replace|source={{FULLPAGENAME}}|­}}}} | sysop = Administrators can't edit this {{NAMESPACE}} page, but still be able to edit pages by autoconfirmed users, users, anonymous users, & temporally accounts. You will <span class="anononly">need to [{{fullurl:Special:UserLogin|returnto={{ urlencode: {{#invoke:String|replace|source={{FULLPAGENAME}}|­}} }}}} log in or create an account] and will</span> be [[Wikipedia:Administrators|administrators]] to create new pages, system messages, & JSON pages. | interfaceadmin = System administrators can't edit this {{NAMESPACE}} page, but still be able to edit pages by autoconfirmed users, users, anonymous users, & temporally accounts. You will <span class="anononly">need to [{{fullurl:Special:UserLogin|returnto={{ urlencode: {{#invoke:String|replace|source={{FULLPAGENAME}}|­}} }}}} log in or create an account] and will </span>be [[Wikipedia:System administrators|system administrators]] to create new CSS & JavaScript pages. | templateeditor = Template editors & administrators can't edit this {{NAMESPACE}} page, but still be able to edit pages by autoconfirmed users, users, anonymous users, & temporally accounts. You will <span class="anononly">need to [{{fullurl:Special:UserLogin|returnto={{ urlencode: {{#invoke:String|replace|source={{FULLPAGENAME}}|­}} }}}} log in or create an account] and will</span> be [[WP:Template editor|template editors]] to create new pages. | extendedconfirmed = Extended confirmed users & administrators can't edit this {{NAMESPACE}} page, but still be able to edit pages by autoconfirmed users, users, anonymous users, & temporally accounts. You will <span class="anononly">need to [{{fullurl:Special:UserLogin|returnto={{ urlencode: {{#invoke:String|replace|source={{FULLPAGENAME}}|­}} }}}} log in or create an account] and will</span> be [[Wikipedia:User access levels#Extendedconfirmed|extended confirmed users]] to create new pages. | autoconfirmed = Autoconfirmed users can't edit this {{NAMESPACE}} page, but still be able to edit pages by users, anonymous users, & temporally accounts. You will <span class="anononly">need to [{{fullurl:Special:UserLogin|returnto={{ urlencode: {{#invoke:String|replace|source={{FULLPAGENAME}}|­}} }}}} log in or create an account] and will </span>be [[WP:User access levels#Autoconfirmed users|autoconfirmed users]] to create new pages. (After 4 days & 10 edits on English Wikipedia.) | user = Some users can't edit this {{NAMESPACE}} page, but still be able to edit pages by anonymous users & temporally accounts. You will need to [{{fullurl:Special:UserLogin|returnto={{ urlencode: {{#invoke:String|replace|source={{FULLPAGENAME}}|­}} }}}} log in or create an account] to make this page. {{#ifeq:{{NAMESPACE}}|{{ns:Category}}|Or, you can [[Wikipedia:Articles for creation/Categories|request the creation of a new category]].}} | #default = Users with the "Create" permission can't edit this {{NAMESPACE}} page. (You do not have permission to create this page when not logged in). You will need to [{{fullurl:Special:UserLogin|returnto={{ urlencode: {{#invoke:String|replace|source={{FULLPAGENAME}}|­}} }}}} log in or create an account] and will be [[WP:User access levels#Autoconfirmed users|autoconfirmed users]] to make your own page. }} |{{#ifeq:{{#invoke:Title blacklist|main|action=create|pagename={{#invoke:String|replace|source={{FULLPAGENAME}}|­}}}}|templateeditor|* Administrators, template editors, & page movers can't edit this {{NAMESPACE}} page, but still be able to edit pages by autoconfirmed users, users, anonymous users, & temporally accounts. You will need to [{{fullurl:Special:UserLogin|returnto={{ urlencode: {{#invoke:String|replace|source={{FULLPAGENAME}}|­}} }}}} log in or create an account] and will be [[Wikipedia:Administrators|administrators]], [[Wikipedia:Template editors|template editors]], & [[Wikipedia:Page movers|page movers]] to create new ones.|* ''' {{ #switch: {{NAMESPACE}} | {{ns:3}} = {{#ifeq:{{ROOTPAGENAME}}|{{PAGENAME}}|[[Special:Edit/{{FULLPAGENAME}}|Post a message to ''{{#invoke:String|replace|source={{PAGENAME}}|­}}]]''|[[Special:Edit/{{FULLPAGENAME}}|Start the ''{{#invoke:String|replace|source={{FULLPAGENAME}}|­}}'' page]] or [[Special:NewSection/{{FULLPAGENAME}}|leave a message about the ''{{#invoke:String|replace|source={{SUBJECTPAGENAME}}|­}}]]''}} | {{ns:5}} | {{ns:7}} | {{ns:9}} | {{ns:11}} | {{ns:13}} | {{ns:15}} | {{ns:101}} | {{ns:119}} | {{ns:711}} | {{ns:829}} | {{ns:1}} = [[Special:Edit/{{FULLPAGENAME}}|Start the ''{{#invoke:String|replace|source={{FULLPAGENAME}}|­}}'' page]] or [[Special:NewSection/{{FULLPAGENAME}}|leave a message about the ''{{#invoke:String|replace|source={{SUBJECTPAGENAME}}|­}}]]'' | {{ns:Category}} = [[Special:Edit/{{FULLPAGENAME}}|Start the ''{{#invoke:String|replace|source={{FULLPAGENAME}}|}}'']] | {{ns:Project}} = [[Special:Edit/{{FULLPAGENAME}}|Start the ''{{#invoke:String|replace|source={{FULLPAGENAME}}|­}}'' page]] or [[Special:NewSection/{{FULLPAGENAME}}|start a discussion about the ''{{#invoke:String|replace|source={{FULLPAGENAME}}|­}}]]'' | #default = [[Special:Edit/{{FULLPAGENAME}}|Start the ''{{#invoke:String|replace|source={{FULLPAGENAME}}|}}'' page]] }}''' {{ #if: {{NAMESPACE}} |by using the '''"[[Wikipedia:Namespaces|{{NAMESPACE}}]]"''' namespace|by using the '''"[[Wikipedia:Namespaces|Page]]"''' namespace, using the [[Wikipedia:Article wizard|Article Wizard]] if you want to create it & submit it for review, or [[{{ns:Project}}:Requested articles|add a request for the new page]] }}.}} }}{{ #switch: {{NAMESPACE}} | {{ns:0}} = * {{plain link|url=https://test.wikipedia.org/w/index.php?search={{urlencode:{{#titleparts:{{#invoke:String|replace|source={{PAGENAME}}|­}}}}}}&title=Special%3ASearch&fulltext=1&ns{{NAMESPACENUMBER}}=1|name=Search for "''{{#invoke:String|replace|source={{PAGENAME}}|­}}''"}} in existing pages. * [[wiktionary:en:Special:Search/{{FULLPAGENAME}}|Look for "{{FULLPAGENAME}}"]] in Wiktionary, our sister dictionary project. * [[commons:Special:Search/{{FULLPAGENAME}}|Look for "{{FULLPAGENAME}}"]] in the Wikimedia Commons, our repository for free images, music, sound, and video. | {{ns:User}} = * [[{{ns:Special}}:WhatLinksHere/{{#invoke:String|replace|source={{FULLPAGENAME}}|­}}|Look for pages within the Test Wikipedia that link to this user page]]. | {{ns:User talk}} = * [[{{ns:Special}}:WhatLinksHere/{{#invoke:String|replace|source={{FULLPAGENAME}}|­}}|Look for pages within the Test Wikipedia that link to this user talk page]]. | {{ns:Category}} = * {{plain link|url=https://test.wikipedia.org/w/index.php?search={{urlencode:{{#titleparts:{{#invoke:String|replace|source={{PAGENAME}}|­}}}}}}&title=Special%3ASearch&fulltext=1&ns{{NAMESPACENUMBER}}=1|name=Search for "''{{#invoke:String|replace|source={{PAGENAME}}|­}}''"}} in existing categories. * [[wiktionary:en:Special:Search/{{FULLPAGENAME}}|Look for "{{FULLPAGENAME}}"]] in Wiktionary, our sister dictionary project. * [[commons:Special:Search/{{FULLPAGENAME}}|Look for "{{FULLPAGENAME}}"]] in the Wikimedia Commons, our repository for free images, music, sound, and video. | {{ns:File}} = * {{plain link|url=https://test.wikipedia.org/w/index.php?search={{urlencode:{{#titleparts:{{#invoke:String|replace|source={{PAGENAME}}|­}}}}}}&title=Special%3ASearch&fulltext=1&ns{{NAMESPACENUMBER}}=1|name=Search for "''{{#invoke:String|replace|source={{PAGENAME}}|­}}''"}} in existing files. * [[commons:Special:Search/{{FULLPAGENAME}}|Look for "{{FULLPAGENAME}}"]] in the Wikimedia Commons, our repository for free images, music, sound, and video. | {{ns:Template}} = * {{plain link|url=https://test.wikipedia.org/w/index.php?search={{urlencode:{{#titleparts:{{#invoke:String|replace|source={{PAGENAME}}|­}}}}}}&title=Special%3ASearch&fulltext=1&ns{{NAMESPACENUMBER}}=1|name=Search for "''{{#invoke:String|replace|source={{PAGENAME}}|­}}''"}} in existing templates. * [[wikimedia:Special:Search/{{FULLPAGENAME}}|Look for "{{FULLPAGENAME}}"]] in Wikimedia, the Free Templates, Categories, & More! | #default = * {{plain link|url=https://test.wikipedia.org/w/index.php?search={{urlencode:{{#titleparts:{{#invoke:String|replace|source={{PAGENAME}}|­}}}}}}&title=Special%3ASearch&fulltext=1&ns{{NAMESPACENUMBER}}=1|name=Search for "''{{#invoke:String|replace|source={{PAGENAME}}|­}}''"}} in existing {{#if: {{NAMESPACE}} | pages with the '''"[[{{ns:Project}}:Namespaces|{{NAMESPACE}}]]"''' namespace | pages without using [[{{ns:Project}}:Namespaces|namespaces]] }}. * [[{{ns:Special}}:WhatLinksHere/{{#invoke:String|replace|source={{FULLPAGENAME}}|­}}|Look for pages within the Test Wikipedia that link to this title]]. }} * {{ #ifeq: {{NAMESPACE}} | {{TALKSPACE}} | You can go back to your [[:{{SUBJECTPAGENAME}}|subject page]] | Please discuss changes on your [[{{TALKPAGENAME}}|talk page]] }}. <div id="noarticletext_technical"> ---- '''Other reasons that may be displayed this message:''' * If {{ #ifeq: {{NAMESPACE}} | {{ns:File}} | a file | a page }} was recently edited here, it may be invisible. (Because of a delay in updating the database.) You can wait a few minutes to complete, you can [[Special:Purge/{{FULLPAGENAME}}|click it]] for purging, or you may want to [[Special:Protect/{{FULLPAGENAME}}|protect]] this page. You can also want to [[Special:Edit/{{FULLPAGENAME}}|edit this page]] or [[Special:Delete/{{FULLPAGENAME}}|delete this page]]. * Titles on the Test Wikipedia is in the '''[[w:en:Case sensitivity|case sensitivity]]''' except for this first character; please {{plain link|url=https://test.wikipedia.org/w/index.php?search={{urlencode:{{#titleparts:{{#invoke:String|replace|source={{FULLPAGENAME}}|­}}}}}}&title=Special%3ASearch&fulltext=1|name=check the Test Wikipedia's alternative capitalizations}} and consider adding some [[Wikipedia:Redirects|redirects]] here to the correct title. If the page you are looking for is not TestSite, see its corresponding [[w:en:Main Page|language Wikipedia]]. If the page is not a [[w:en:test wiki|test wiki]], check one of the [[wikimedia:Main Page|other Foundation wikis]]. * If this page has been deleted, try [{{fullurl:Special:Log/delete|page={{#invoke:String|replace|source={{FULLPAGENAMEE}}|­}}}} checking the '''deletion log'''], and see [[Wikipedia:Why was the page I created deleted?|the Why was the page I created deleted?]] for possible reasons. </div> }} <!--End fmbox --><!--Start book box-->{{#if:{{#invoke:String|match|{{FULLPAGENAME}}|^Book:|nomatch= }}{{#invoke:String|match|{{FULLPAGENAME}}|^Book talk:|nomatch= }}|{{fmbox|type=system|text=<strong>This page may have existed as part of the former book & talk namespace.</strong> If so it was likely moved to [[{{#invoke:String|replace|{{#invoke:String|replace|{{FULLPAGENAME}}|^Book talk:|Book:|plain=False}}|^Book:|Wikipedia:Books/archive/|plain=False}}]] before being deleted. See [[Wikipedia:Books]] for more information.}}}}<!--End book box--> </div> == {{ #switch: {{NAMESPACE}} | {{ns:0}} = Page | {{ns:Talk}} = [[{{ns:Help}}:Using talk pages|Discussion page]] | {{TALKSPACE}} = [[{{ns:Help}}:Using talk pages|{{SUBJECTSPACE}}'s Discussion page]] | {{ns:Category}} = [[{{ns:Project}}:Categorization|Category]] | {{ns:Help}} = [[{{ns:Help}}:Contents|Help page]] | {{ns:File}} = [[{{ns:Project}}:Files to upload|File]] | {{ns:Portal}} = [[{{ns:Project}}:Portal|Portal]] | {{ns:Template}} = [[{{ns:Project}}:Template messages|Template]] | {{ns:User}} = [[{{ns:Project}}:User pages|User page]] | {{ns:Project}} = [[{{ns:Project}}:Project namespace|Project page]] | {{ns:MediaWiki}} = [[Special:AllMessages|System message]] | #default = {{NAMESPACE}} page}} not showing up? == Reload the page you just created "'''{{FULLPAGENAME}}'''." <small>You may also [[Wikipedia:Administrators' noticeboard|contact an administrator]] before recreating this page.</small> If you can't find the page, you can [[Special:Search/{{FULLPAGENAME}}|search for an existing page]] or {{ #ifeq: {{{nopermission}}} | yes | <span class="plainlinks>[{{fullurl:Special:Log|page={{FULLPAGENAME}}}} look for the logs]</span> | [[Special:Edit/{{FULLPAGENAME}}|create it]] }}. {{ #ifeq: {{{nopermission}}} | yes |<div class="mw-parser-output">{{fmbox | type = warning | id = noarticletext | image = none | text = You do not have permission to create this page. It may have been protected from creation. If I think this page should be created here, please unprotect this page at [[Wikipedia:Administrators' noticeboard|the Administrators' noticeboard]].}}</div>|<div class="mw-parser-output">{{fmbox | type = system | id = noarticletext | image = none | text = If you can't find {{FULLPAGENAME}}, you can also include the <span class="planlinks">[{{fullurl:{{FULLPAGENAME}}|veaction=edit}} visual editor]</span>, {{ #ifeq: {{NAMESPACE}} | {{TALKSPACE}} | the <span class="planlinks">[{{fullurl:{{FULLPAGENAME}}|action=edit&veswitched=1}} source editor]</span>, or [[Special:NewSection/{{FULLPAGENAME}}|create a new section]] | or the <span class="planlinks">[{{fullurl:{{FULLPAGENAME}}|action=edit&veswitched=1}} source editor]</span> }} for editing.}}</div>}} <noinclude> {{documentation}} </noinclude> 9d9wtld1ry0ciwq10ha0tfsks50admr 739057 739056 2026-04-22T00:23:37Z Sheffalump 71152 739057 wikitext text/x-wiki <div class="mw-parser-output"><!-- don't touch this div to the left, it makes TemplateStyles vroom vroom --> {{New page DYM}} {{ #ifeq: {{NAMESPACE}} | {{TALKSPACE}} |{{#ifexist: {{SUBJECTPAGENAME}}|This is the talk page for [[:{{SUBJECTPAGENAME}}]].|[[:{{SUBJECTPAGENAME}}]] has not yet been created. {{Viewing talk page without subject}}|}}}} {{fmbox | type = system | id = noarticletext | image = none | textstyle = padding: 0.6em 0.9em; <!--Large box needs more padding--> | text = {{#tag:strong|WARNING:}} {{ #ifeq: {{ #ifeq: {{FULLPAGENAME}} | Template:No article text || }} | <!--Mainspace sister project infobox--> | {{No article text/sister projects}} }}{{ #ifeq: {{NAMESPACE}} | {{ns:User talk}} | {{#tag:strong|No messages}} have been posted for {{BASEPAGENAME}} yet. | {{#tag:strong|Wikipedia does not contain {{ #switch: {{NAMESPACE}} | {{ns:0}} = a {{#tag:em|[[{{ns:Project}}:Using pages without namespaces|page]]}} | {{ns:Talk}} = a {{#tag:em|[[{{ns:Help}}:Using talk pages|discussion page]]}} | {{TALKSPACE}} = the {{#tag:em|[[{{ns:Help}}:Using talk pages|{{SUBJECTSPACE}}'s discussion page]]}} | {{ns:Category}} = a {{#tag:em|[[{{ns:Project}}:Categorization|category]]}} | {{ns:Help}} = a {{#tag:em|[[{{ns:Help}}:Contents|help page]]}} | {{ns:File}} = a {{#tag:em|[[{{ns:Project}}:Files to upload|file]]}} | {{ns:Portal}} = a {{#tag:em|[[{{ns:Project}}:Portal|portal]]}} | {{ns:Template}} = a {{#tag:em|[[{{ns:Project}}:Template messages|template]]}} | {{ns:User}} = a {{#tag:em|[[{{ns:Project}}:User pages|user page]]}} | {{ns:Project}} = a {{#tag:em|[[{{ns:Project}}:Project namespace|project page]]}} | {{ns:MediaWiki}} = a {{#tag:em|[[Special:AllMessages|system message]]}} | #default = a {{#tag:em|[[{{ns:Project}}:Namespaces|{{NAMESPACE}} page]]}} }} with this exact name yet.}} {{ #ifeq: {{#invoke:String|replace|source={{PAGENAME}}|­}} | {{#invoke:String|replace|source={{SUBPAGENAME}}|­}} | {{ #switch: {{NAMESPACE}} | {{ns:0}} = Please {{plain link|url=https://test.wikipedia.org/w/index.php?search={{urlencode:{{#titleparts:{{#invoke:String|replace|source={{PAGENAME}}|­}}}}}}&title=Special%3ASearch&fulltext=1|name=search for ''{{#invoke:String|replace|source={{PAGENAME}}|­}}'' in Test Wikipedia}} to check for alternative titles, names, or spellings. | {{ns:Talk}} = Before creating this page, please verify that a page called [[{{PAGENAME}}]] exists. | {{TALKSPACE}} = Before creating this page, please verify that [[:{{SUBJECTPAGENAME}}]] is already made. | {{ns:Category}} = Please browse the [[Portal:Contents|existing categories]] to check if this category is covered under another name. | {{ns:Help}} = Please browse the [[{{ns:Help}}:Contents|existing help pages]] to check if this help topic is covered under another name. | {{ns:File}} = Please do not manually create this page. If you want to upload ''File:{{PAGENAME}}'', Please see the [[{{ns:Project}}:Files to upload|Files to upload]] for instructions & tutorials. | {{ns:Portal}} = Please browse the [[{{ns:Portal}}:Contents/Portals|existing portals]] to check for similar topics. | {{ns:Template}} = Please browse the [[{{ns:Project}}:Template messages|existing templates]] to check if this standardized message is available under another name. | {{ns:User}} = In general, this page should be created and edited by [[User:{{PAGENAME}}]]. If you're already registered, Please [[Special:UserLogin|log in]]. If you don't have an account, [[Special:CreateAccount|create one]]. If you are {{PAGENAME}}, click [[Special:Edit/User:{{PAGENAME}}|create this page]]. If you are not {{PAGENAME}}, don't click "create this page". | {{ns:Project}} = Please browse the [[{{ns:Project}}:List of policies and guidelines|existing policies and guidelines]] or [[Special:Search/{{ns:Project}}:{{PAGENAME}}|search]] for similar existing project pages. | {{ns:MediaWiki}} = Please browse the [[Special:AllMessages|existing system messages]] to check if this Non-CSS, Non-JavaScript, Non-JSON, CSS, JavaScript, & JSON pages are available under another name. | #default = Please browse the [[{{ns:Project}}:Namespaces|existing {{NAMESPACE}} pages]] to check if this {{NAMESPACE}} namespace is available under another name. }} | {{ #ifeq: {{{nopermission}}} | yes |You do not have permission to edit pages in the {{#if: {{NAMESPACE}} | '''[[Wikipedia:Namespaces|{{NAMESPACE}}]]''' namespace | '''[[Wikipedia:Namespaces|Page]]''' namespace }}. Please [{{fullurl:Special:UserLogin|returnto={{ urlencode: {{#invoke:String|replace|source={{FULLPAGENAME}}|­}} }}}} log in] or [{{fullurl:Special:UserLogin/signup|returnto={{ urlencode: {{#invoke:String|replace|source={{FULLPAGENAME}}|­}} }}}} sign up] if you want to create this page. (This page is currently protected so only administrators, system administrators, template editors, extended confirmed users, page movers, autoconfirmed users, & logged in users can make it, '''not''' temporary accounts or unregistered (IP) users). (If you're logged out, {{SITENAME}} has restricted the ability to create new pages. You can go back and edit an existing page, or [[Special:UserLogin|log in or create an account]]. If you're logged in, You do not have permission to create new pages.) Please see [[{{ns:Project}}:Subpages|Subpages]] for subpages if you do not create it because this isn't needed. To protect the page, click [[Special:Protect/{{FULLPAGENAME}}|protect]].| Before creating this page in the {{#if: {{NAMESPACE}} | '''[[Wikipedia:Namespaces|{{NAMESPACE}}]]''' namespace | '''[[Wikipedia:Namespaces|Page]]''' namespace }}, please see [[{{ns:Project}}:Subpages|Subpages]] for subpages. To protect the page, click [[Special:Protect/{{FULLPAGENAME}}|protect]].}} }} }}{{ #ifeq: {{{nopermission}}} | yes |* {{ #switch: {{#invoke:Effective protection level|create|{{#invoke:String|replace|source={{FULLPAGENAME}}|­}}}} | sysop = Administrators can't edit this {{NAMESPACE}} page, but still be able to edit pages by autoconfirmed users, users, anonymous users, & temporally accounts. You will <span class="anononly">need to [{{fullurl:Special:UserLogin|returnto={{ urlencode: {{#invoke:String|replace|source={{FULLPAGENAME}}|­}} }}}} log in or create an account] and will</span> be [[Wikipedia:Administrators|administrators]] to create new pages, system messages, & JSON pages. | interfaceadmin = System administrators can't edit this {{NAMESPACE}} page, but still be able to edit pages by autoconfirmed users, users, anonymous users, & temporally accounts. You will <span class="anononly">need to [{{fullurl:Special:UserLogin|returnto={{ urlencode: {{#invoke:String|replace|source={{FULLPAGENAME}}|­}} }}}} log in or create an account] and will </span>be [[Wikipedia:System administrators|system administrators]] to create new CSS & JavaScript pages. | templateeditor = Template editors & administrators can't edit this {{NAMESPACE}} page, but still be able to edit pages by autoconfirmed users, users, anonymous users, & temporally accounts. You will <span class="anononly">need to [{{fullurl:Special:UserLogin|returnto={{ urlencode: {{#invoke:String|replace|source={{FULLPAGENAME}}|­}} }}}} log in or create an account] and will</span> be [[WP:Template editor|template editors]] to create new pages. | extendedconfirmed = Extended confirmed users & administrators can't edit this {{NAMESPACE}} page, but still be able to edit pages by autoconfirmed users, users, anonymous users, & temporally accounts. You will <span class="anononly">need to [{{fullurl:Special:UserLogin|returnto={{ urlencode: {{#invoke:String|replace|source={{FULLPAGENAME}}|­}} }}}} log in or create an account] and will</span> be [[Wikipedia:User access levels#Extendedconfirmed|extended confirmed users]] to create new pages. | autoconfirmed = Autoconfirmed users can't edit this {{NAMESPACE}} page, but still be able to edit pages by users, anonymous users, & temporally accounts. You will <span class="anononly">need to [{{fullurl:Special:UserLogin|returnto={{ urlencode: {{#invoke:String|replace|source={{FULLPAGENAME}}|­}} }}}} log in or create an account] and will </span>be [[WP:User access levels#Autoconfirmed users|autoconfirmed users]] to create new pages. (After 4 days & 10 edits on English Wikipedia.) | user = Some users can't edit this {{NAMESPACE}} page, but still be able to edit pages by anonymous users & temporally accounts. You will need to [{{fullurl:Special:UserLogin|returnto={{ urlencode: {{#invoke:String|replace|source={{FULLPAGENAME}}|­}} }}}} log in or create an account] to make this page. {{#ifeq:{{NAMESPACE}}|{{ns:Category}}|Or, you can [[Wikipedia:Articles for creation/Categories|request the creation of a new category]].}} | #default = Users with the "Create" permission can't edit this {{NAMESPACE}} page. (You do not have permission to create this page when not logged in). You will need to [{{fullurl:Special:UserLogin|returnto={{ urlencode: {{#invoke:String|replace|source={{FULLPAGENAME}}|­}} }}}} log in or create an account] and will be [[WP:User access levels#Autoconfirmed users|autoconfirmed users]] to make your own page. }} |{{#ifeq:{{#invoke:Title blacklist|main|action=create|pagename={{#invoke:String|replace|source={{FULLPAGENAME}}|­}}}}|templateeditor|* Administrators, template editors, & page movers can't edit this {{NAMESPACE}} page, but still be able to edit pages by autoconfirmed users, users, anonymous users, & temporally accounts. You will need to [{{fullurl:Special:UserLogin|returnto={{ urlencode: {{#invoke:String|replace|source={{FULLPAGENAME}}|­}} }}}} log in or create an account] and will be [[Wikipedia:Administrators|administrators]], [[Wikipedia:Template editors|template editors]], & [[Wikipedia:Page movers|page movers]] to create new ones.|* ''' {{ #switch: {{NAMESPACE}} | {{ns:3}} = {{#ifeq:{{ROOTPAGENAME}}|{{PAGENAME}}|[[Special:Edit/{{FULLPAGENAME}}|Post a message to ''{{#invoke:String|replace|source={{PAGENAME}}|­}}]]''|[[Special:Edit/{{FULLPAGENAME}}|Start the ''{{#invoke:String|replace|source={{FULLPAGENAME}}|­}}'' page]] or [[Special:NewSection/{{FULLPAGENAME}}|leave a message about the ''{{#invoke:String|replace|source={{SUBJECTPAGENAME}}|­}}]]''}} | {{ns:5}} | {{ns:7}} | {{ns:9}} | {{ns:11}} | {{ns:13}} | {{ns:15}} | {{ns:101}} | {{ns:119}} | {{ns:711}} | {{ns:829}} | {{ns:1}} = [[Special:Edit/{{FULLPAGENAME}}|Start the ''{{#invoke:String|replace|source={{FULLPAGENAME}}|­}}'' page]] or [[Special:NewSection/{{FULLPAGENAME}}|leave a message about the ''{{#invoke:String|replace|source={{SUBJECTPAGENAME}}|­}}]]'' | {{ns:Category}} = [[Special:Edit/{{FULLPAGENAME}}|Start the ''{{#invoke:String|replace|source={{FULLPAGENAME}}|}}'']] | {{ns:Project}} = [[Special:Edit/{{FULLPAGENAME}}|Start the ''{{#invoke:String|replace|source={{FULLPAGENAME}}|­}}'' page]] or [[Special:NewSection/{{FULLPAGENAME}}|start a discussion about the ''{{#invoke:String|replace|source={{FULLPAGENAME}}|­}}]]'' | #default = [[Special:Edit/{{FULLPAGENAME}}|Start the ''{{#invoke:String|replace|source={{FULLPAGENAME}}|}}'' page]] }}''' {{ #if: {{NAMESPACE}} |by using the '''"[[Wikipedia:Namespaces|{{NAMESPACE}}]]"''' namespace|by using the '''"[[Wikipedia:Namespaces|Page]]"''' namespace, using the [[Wikipedia:Article wizard|Article Wizard]] if you want to create it & submit it for review, or [[{{ns:Project}}:Requested articles|add a request for the new page]] }}.}} }}{{ #switch: {{NAMESPACE}} | {{ns:0}} = * {{plain link|url=https://test.wikipedia.org/w/index.php?search={{urlencode:{{#titleparts:{{#invoke:String|replace|source={{PAGENAME}}|­}}}}}}&title=Special%3ASearch&fulltext=1&ns{{NAMESPACENUMBER}}=1|name=Search for "''{{#invoke:String|replace|source={{PAGENAME}}|­}}''"}} in existing pages. * [[wiktionary:en:Special:Search/{{FULLPAGENAME}}|Look for "{{FULLPAGENAME}}"]] in Wiktionary, our sister dictionary project. * [[commons:Special:Search/{{FULLPAGENAME}}|Look for "{{FULLPAGENAME}}"]] in the Wikimedia Commons, our repository for free images, music, sound, and video. | {{ns:User}} = * [[{{ns:Special}}:WhatLinksHere/{{#invoke:String|replace|source={{FULLPAGENAME}}|­}}|Look for pages within the Test Wikipedia that link to this user page]]. | {{ns:User talk}} = * [[{{ns:Special}}:WhatLinksHere/{{#invoke:String|replace|source={{FULLPAGENAME}}|­}}|Look for pages within the Test Wikipedia that link to this user talk page]]. | {{ns:Category}} = * {{plain link|url=https://test.wikipedia.org/w/index.php?search={{urlencode:{{#titleparts:{{#invoke:String|replace|source={{PAGENAME}}|­}}}}}}&title=Special%3ASearch&fulltext=1&ns{{NAMESPACENUMBER}}=1|name=Search for "''{{#invoke:String|replace|source={{PAGENAME}}|­}}''"}} in existing categories. * [[wiktionary:en:Special:Search/{{FULLPAGENAME}}|Look for "{{FULLPAGENAME}}"]] in Wiktionary, our sister dictionary project. * [[commons:Special:Search/{{FULLPAGENAME}}|Look for "{{FULLPAGENAME}}"]] in the Wikimedia Commons, our repository for free images, music, sound, and video. | {{ns:File}} = * {{plain link|url=https://test.wikipedia.org/w/index.php?search={{urlencode:{{#titleparts:{{#invoke:String|replace|source={{PAGENAME}}|­}}}}}}&title=Special%3ASearch&fulltext=1&ns{{NAMESPACENUMBER}}=1|name=Search for "''{{#invoke:String|replace|source={{PAGENAME}}|­}}''"}} in existing files. * [[commons:Special:Search/{{FULLPAGENAME}}|Look for "{{FULLPAGENAME}}"]] in the Wikimedia Commons, our repository for free images, music, sound, and video. | {{ns:Template}} = * {{plain link|url=https://test.wikipedia.org/w/index.php?search={{urlencode:{{#titleparts:{{#invoke:String|replace|source={{PAGENAME}}|­}}}}}}&title=Special%3ASearch&fulltext=1&ns{{NAMESPACENUMBER}}=1|name=Search for "''{{#invoke:String|replace|source={{PAGENAME}}|­}}''"}} in existing templates. * [[wikimedia:Special:Search/{{FULLPAGENAME}}|Look for "{{FULLPAGENAME}}"]] in Wikimedia, the Free Templates, Categories, & More! | #default = * {{plain link|url=https://test.wikipedia.org/w/index.php?search={{urlencode:{{#titleparts:{{#invoke:String|replace|source={{PAGENAME}}|­}}}}}}&title=Special%3ASearch&fulltext=1&ns{{NAMESPACENUMBER}}=1|name=Search for "''{{#invoke:String|replace|source={{PAGENAME}}|­}}''"}} in existing {{#if: {{NAMESPACE}} | pages with the '''"[[{{ns:Project}}:Namespaces|{{NAMESPACE}}]]"''' namespace | pages without using [[{{ns:Project}}:Namespaces|namespaces]] }}. * [[{{ns:Special}}:WhatLinksHere/{{#invoke:String|replace|source={{FULLPAGENAME}}|­}}|Look for pages within the Test Wikipedia that link to this title]]. }} * {{ #ifeq: {{NAMESPACE}} | {{TALKSPACE}} | You can go back to your [[:{{SUBJECTPAGENAME}}|subject page]] | Please discuss changes on your [[{{TALKPAGENAME}}|talk page]] }}. <div id="noarticletext_technical"> ---- '''Other reasons that may be displayed this message:''' * If {{ #ifeq: {{NAMESPACE}} | {{ns:File}} | a file | a page }} was recently edited here, it may be invisible. (Because of a delay in updating the database.) You can wait a few minutes to complete, you can [[Special:Purge/{{FULLPAGENAME}}|click it]] for purging, or you may want to [[Special:Protect/{{FULLPAGENAME}}|protect]] this page. You can also want to [[Special:Edit/{{FULLPAGENAME}}|edit this page]] or [[Special:Delete/{{FULLPAGENAME}}|delete this page]]. * Titles on the Test Wikipedia is in the '''[[w:en:Case sensitivity|case sensitivity]]''' except for this first character; please {{plain link|url=https://test.wikipedia.org/w/index.php?search={{urlencode:{{#titleparts:{{#invoke:String|replace|source={{FULLPAGENAME}}|­}}}}}}&title=Special%3ASearch&fulltext=1|name=check the Test Wikipedia's alternative capitalizations}} and consider adding some [[Wikipedia:Redirects|redirects]] here to the correct title. If the page you are looking for is not TestSite, see its corresponding [[w:en:Main Page|language Wikipedia]]. If the page is not a [[w:en:test wiki|test wiki]], check one of the [[wikimedia:Main Page|other Foundation wikis]]. * If this page has been deleted, try [{{fullurl:Special:Log/delete|page={{#invoke:String|replace|source={{FULLPAGENAMEE}}|­}}}} checking the '''deletion log'''], and see [[Wikipedia:Why was the page I created deleted?|the Why was the page I created deleted?]] for possible reasons. </div> }} <!--End fmbox --><!--Start book box-->{{#if:{{#invoke:String|match|{{FULLPAGENAME}}|^Book:|nomatch= }}{{#invoke:String|match|{{FULLPAGENAME}}|^Book talk:|nomatch= }}|{{fmbox|type=system|text=<strong>This page may have existed as part of the former book & talk namespace.</strong> If so it was likely moved to [[{{#invoke:String|replace|{{#invoke:String|replace|{{FULLPAGENAME}}|^Book talk:|Book:|plain=False}}|^Book:|Wikipedia:Books/archive/|plain=False}}]] before being deleted. See [[Wikipedia:Books]] for more information.}}}}<!--End book box--> </div> == {{ #switch: {{NAMESPACE}} | {{ns:0}} = Page | {{ns:Talk}} = [[{{ns:Help}}:Using talk pages|Discussion page]] | {{TALKSPACE}} = [[{{ns:Help}}:Using talk pages|{{SUBJECTSPACE}}'s Discussion page]] | {{ns:Category}} = [[{{ns:Project}}:Categorization|Category]] | {{ns:Help}} = [[{{ns:Help}}:Contents|Help page]] | {{ns:File}} = [[{{ns:Project}}:Files to upload|File]] | {{ns:Portal}} = [[{{ns:Project}}:Portal|Portal]] | {{ns:Template}} = [[{{ns:Project}}:Template messages|Template]] | {{ns:User}} = [[{{ns:Project}}:User pages|User page]] | {{ns:Project}} = [[{{ns:Project}}:Project namespace|Project page]] | {{ns:MediaWiki}} = [[Special:AllMessages|System message]] | #default = {{NAMESPACE}} page}} not showing up? == Reload the page you just created "'''{{FULLPAGENAME}}'''." <small>You may also [[Wikipedia:Administrators' noticeboard|contact an administrator]] before recreating this page.</small> If you can't find the page, you can [[Special:Search/{{FULLPAGENAME}}|search for an existing page]] or {{ #ifeq: {{{nopermission}}} | yes | <span class="plainlinks">[{{fullurl:{{#Special:Log}}|page={{urlencode:{{FULLPAGENAME}}}}}} search the related logs]</span> | [[Special:Edit/{{FULLPAGENAME}}|create it]] }}. {{ #ifeq: {{{nopermission}}} | yes |<div class="mw-parser-output">{{fmbox | type = warning | id = noarticletext | image = none | text = You do not have permission to create this page. It may have been protected from creation. If I think this page should be created here, please unprotect this page at [[Wikipedia:Administrators' noticeboard|the Administrators' noticeboard]].}}</div>|<div class="mw-parser-output">{{fmbox | type = system | id = noarticletext | image = none | text = If you can't find {{FULLPAGENAME}}, you can also include the <span class="planlinks">[{{fullurl:{{FULLPAGENAME}}|veaction=edit}} visual editor]</span>, {{ #ifeq: {{NAMESPACE}} | {{TALKSPACE}} | the <span class="planlinks">[{{fullurl:{{FULLPAGENAME}}|action=edit&veswitched=1}} source editor]</span>, or [[Special:NewSection/{{FULLPAGENAME}}|create a new section]] | or the <span class="planlinks">[{{fullurl:{{FULLPAGENAME}}|action=edit&veswitched=1}} source editor]</span> }} for editing.}}</div>}} <noinclude> {{documentation}} </noinclude> 0m9c6fikoomehqiuch8tn1irscl3450 User:Sam Sailor/test.js 2 98186 739070 739007 2026-04-22T05:57:20Z Sam Sailor 26820 Test 739070 javascript text/javascript //<nowiki> (function() { if (window.Headmaster) return; const defaultNS = [0, 2, 10, 118]; const userNS = window.headmaster_ns || []; const config = { menu: window.headmaster_menu || 'p-cactions', enableSummary: window.headmaster_do_summary !== false, customSummary: window.headmaster_summary || "", allowedNamespaces: Array.from(new Set([...defaultNS, ...userNS])), autoScan: window.headmaster_auto_scan !== false, autoRun: window.headmaster_auto_run === true }; const Headmaster = { VERSION: "0.9.1", DefaultSummary: "Converting [[MOS:PSEUDOHEAD|pseudo-headings]] {details}using [[User:Sam_Sailor/Scripts/Headmaster.js|Headmaster]]. Semicolon markup is reserved for [[MOS:DLIST|description lists]].", styleInjected: false, css: ` #hm-panel { clear: both; border: 1px solid #a2a9b1; padding: 15px; background: #f8f9fa; margin-bottom: 1.5em; border-radius: 2px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); } #hm-table { width: 100%; border-collapse: collapse; background: white; margin-top: 10px; } #hm-table th { background: #f2f2f2; border: 1px solid #a2a9b1; padding: 8px; text-align: left; } #hm-table td { border: 1px solid #a2a9b1; padding: 8px; vertical-align: middle; } .hm-context { font-family: 'Courier New', monospace; font-size: 0.9em; color: #54595d; background: #fdfdfd; } #hm-controls { display: flex; justify-content: space-between; align-items: center; margin-top: 15px; } #hm-controls button { margin-left: 10px; padding: 6px 16px; cursor: pointer; border-radius: 2px; } .hm-btn-apply { background: #36c; color: white; border: 1px solid #36c; font-weight: bold; } .hm-btn-apply:hover { background: #447ff5; } .hm-global-selector { font-size: 0.9em; color: #202122; background: #eaecf0; padding: 8px; border-radius: 2px; border: 1px solid #a2a9b1; } .hm-global-selector a { font-weight: bold; text-decoration: none; color: #36c; } .hm-global-selector a:hover { text-decoration: underline; } .hm-locate-btn { cursor: pointer; color: #36c; border: 1px solid #a2a9b1; background: #f8f9fa; padding: 2px 6px; font-size: 0.85em; border-radius: 2px; } .hm-locate-btn:hover { background: #fff; border-color: #36c; } `, setup() { if (!config.allowedNamespaces.includes(mw.config.get("wgNamespaceNumber"))) return; const action = mw.config.get("wgAction"); this.addPortlet(action); if (action === 'view' && (config.autoScan || config.autoRun)) { this.silentScan(); } if (mw.util.getParamValue('headmaster') === '1' && ['edit', 'submit'].includes(action)) { const params = new URLSearchParams(window.location.search); params.delete('headmaster'); const searchString = params.toString(); const newUrl = window.location.pathname + (searchString ? '?' + searchString : ''); window.history.replaceState(null, '', newUrl); this.init(); } }, addPortlet(action) { const link = mw.util.addPortletLink(config.menu, '#', 'Headmaster', 'ca-hm', 'Interactively convert pseudo-headings'); if (link) { $(link).on('click', (e) => { e.preventDefault(); if (action === 'view') { this.redirectToEdit(); } else if (['edit', 'submit'].includes(action)) { this.init(); } }); } }, redirectToEdit() { window.location.href = mw.util.getUrl(mw.config.get("wgPageName"), { action: 'edit', headmaster: '1' }); }, silentScan() { new mw.Api().get({ action: 'query', prop: 'revisions', titles: mw.config.get('wgPageName'), rvprop: 'content', rvlimit: 1, formatversion: 2 }).done((data) => { const page = data.query.pages[0]; if (!page || !page.revisions) return; const wikitext = page.revisions[0].content; const tasks = this.analyzeText(wikitext); if (tasks.length > 0) { if (config.autoRun) { this.redirectToEdit(); } else { this.notifyDiscovery(tasks.length); } } }); }, notifyDiscovery(count) { const $msg = $('<span>').text(`Headmaster: Found ${count} pseudo-headings. `).append($('<a>').text('Run conversion').css({ fontWeight: 'bold', cursor: 'pointer' }).on('click', () => this.redirectToEdit())); mw.notify($msg, { tag: 'hm-discovery', autoHide: false }); }, init() { if (!this.styleInjected) { mw.loader.addStyleTag(this.css); this.styleInjected = true; } const $textbox = $('#wpTextbox1'); const wikitext = $textbox.textSelection('getContents'); if (!wikitext) { mw.notify("Textbox is empty or not found.", { type: 'error' }); return; } const tasks = this.analyzeText(wikitext); if (tasks.length === 0) { mw.notify("No pseudo-headings found."); return; } this.showUI(tasks, wikitext); }, analyzeText(wikitext) { const lines = wikitext.split("\n"); const tasks = []; let currentDepth = 2; for (let i = 0; i < lines.length; i++) { const line = lines[i].trim(); const headingMatch = line.match(/^(={2,6})\s*.+?\s*\1\s*$/); if (headingMatch) currentDepth = headingMatch[1].length; if (line.startsWith(';') && !line.startsWith(';;')) { const nextLine = lines[i + 1] || ""; if (!nextLine.trim().startsWith(':')) { const cleanText = lines[i].substring(1).replace(/\s*:.*$/, "").trim(); const suggestedLevel = "=".repeat(Math.min(currentDepth + 1, 6)); tasks.push({ index: i, original: lines[i], cleanText: cleanText, context: nextLine.substring(0, 60).trim() + (nextLine.length > 60 ? "..." : ""), suggestedLevel: suggestedLevel }); } } } return tasks; }, showUI(tasks, originalWikitext) { $('#hm-panel').remove(); $('#editform').hide(); const tableRows = tasks.map((task, i) => ` <tr data-task-index="${task.index}"> <td><button class="hm-locate-btn" data-hm-i="${i}" title="Show in editor">Locate</button></td> <td class="hm-context"><code>${mw.html.escape(task.original)}</code></td> <td><label><input type="radio" name="hm-opt-${i}" value="keep"> Keep</label></td> <td><label><input type="radio" name="hm-opt-${i}" value="bold" checked> <b>Bold</b></label></td> <td><label><input type="radio" name="hm-opt-${i}" value="head"> Heading (${task.suggestedLevel.length})</label></td> <td class="hm-context">${mw.html.escape(task.context || "(end of page)")}</td> </tr> `).join(""); const $panel = $(` <div id="hm-panel"> <h3 style="margin-top:0">Headmaster v${this.VERSION}: Review pseudo-headings</h3> <div class="hm-global-selector"> <strong>Bulk action:</strong> <a href="#" id="hm-all-keep">Set all to Keep</a> | <a href="#" id="hm-all-bold">Set all to Bold</a> | <a href="#" id="hm-all-head">Set all to Heading</a> </div> <table id="hm-table"> <thead> <tr> <th>Find</th> <th>Source</th> <th colspan="3">Action</th> <th>Next line context</th> </tr> </thead> <tbody>${tableRows}</tbody> </table> <div id="hm-controls"> <span>Found <strong>${tasks.length}</strong> possible pseudo-headings.</span> <div> <button id="hm-cancel" class="mw-ui-button">Cancel</button> <button id="hm-apply" class="hm-btn-apply">Show changes (diff)</button> </div> </div> </div> `); $('#content').prepend($panel); window.scrollTo(0, 0); $('.hm-locate-btn').on('click', function() { $(document).off('mousedown.hmlocate'); const idx = $(this).data('hm-i'); const task = tasks[idx]; const lines = originalWikitext.split('\n'); let charOffset = 0; for (let j = 0; j < task.index; j++) { charOffset += lines[j].length + 1; } $('#hm-panel').hide(); $('#editform').show(); const $textbox = $('#wpTextbox1'); $textbox.textSelection('setSelection', { start: charOffset, end: charOffset + lines[task.index].length }); $textbox.textSelection('scrollToCaretPosition'); const locateNotify = mw.notify("Locating line " + (task.index + 1) + ". Click outside the editor to return.", { tag: 'hm-locate', type: 'success', autoHide: false }); setTimeout(() => { $(document).on('mousedown.hmlocate', function(e) { if (!$(e.target).closest('#editform, .mw-notification-area').length) { $(document).off('mousedown.hmlocate'); locateNotify.then(n => n.close()); $('#editform').hide(); $('#hm-panel').show(); } }); }, 200); }); $('#hm-all-keep').on('click', (e) => { e.preventDefault(); $('input[value="keep"]').prop('checked', true); }); $('#hm-all-bold').on('click', (e) => { e.preventDefault(); $('input[value="bold"]').prop('checked', true); }); $('#hm-all-head').on('click', (e) => { e.preventDefault(); $('input[value="head"]').prop('checked', true); }); $('#hm-cancel').on('click', () => { $('#hm-panel').remove(); $('#editform').show(); }); $('#hm-apply').on('click', () => this.applyChanges(tasks, originalWikitext)); }, getProcessedSummary(existingSummary, bolds, heads) { if (!config.enableSummary) return existingSummary; let mySummary, isDefault = false; if (config.customSummary) { mySummary = config.customSummary; } else { isDefault = true; const detailsArr = []; if (bolds > 0) detailsArr.push(`${bolds} to bold`); if (heads > 0) detailsArr.push(`${heads} to heading`); const detailsStr = detailsArr.length > 0 ? `(${detailsArr.join(', ')}) ` : ""; mySummary = this.DefaultSummary.replace("{details}", detailsStr); } const trimmedOld = existingSummary.trim(); if (!trimmedOld) return mySummary; if (/[.!?]$/.test(trimmedOld)) { return trimmedOld + " " + mySummary; } else { const finalSummary = isDefault ? mySummary.charAt(0).toLowerCase() + mySummary.slice(1) : mySummary; return trimmedOld + "; " + finalSummary; } }, applyChanges(tasks, wikitext) { try { const lines = wikitext.split("\n"); let bCount = 0, hCount = 0; $('#hm-table tbody tr').each(function(i) { const action = $(this).find('input:checked').val(); const task = tasks[i]; if (action === 'bold') { lines[task.index] = `'''${task.cleanText}'''`; bCount++; } else if (action === 'head') { const h = task.suggestedLevel; lines[task.index] = `${h} ${task.cleanText} ${h}`; hCount++; } }); if (bCount + hCount === 0) { mw.notify("No changes selected."); $('#hm-panel').remove(); $('#editform').show(); return; } const $textbox = $('#wpTextbox1'); const $summary = $('#wpSummary'); $textbox.textSelection('setContents', lines.join("\n")); $summary.val(this.getProcessedSummary($summary.val(), bCount, hCount)); $('#hm-panel').remove(); $('#editform').show(); $('#wpDiff').click(); } catch (err) { $('#editform').show(); mw.notify("Headmaster error: " + err.message, { type: 'error' }); } } }; window.Headmaster = Headmaster; mw.loader.using(['mediawiki.util', 'mediawiki.api', 'jquery.textSelection'], () => { $(() => Headmaster.setup()); }); })(); (function() { var Comrade = Comrade || {}; mw.util.addCSS(` .ambox-Orphan { display: block !important; } .comrade-container { box-shadow: 0 1px 3px rgba(0,0,0,0.1); border-radius: 2px; padding: 10px 15px; margin: 10px 0; display: flex; flex-direction: column; align-items: flex-start; gap: 8px; border: 1px solid #a2a9b1; background: #fcfcfc; line-height: 1.5; } .comrade-header { display: flex; align-items: center; justify-content: space-between; width: 100%; } .comrade-content { display: flex; flex-direction: column; gap: 5px; width: 100%; } .comrade-success { background-color: #d5f5e3 !important; border-left: 5px solid #27ae60 !important; color: #1b5e20 !important; } .comrade-nudge { background: #fff9ea; border-left: 5px solid #f0ad4e; } .comrade-info { background: #eaf3ff; border-left: 5px solid #36c; } .comrade-status { background: #eaf3ff; border-left: 5px solid #36c; } .comrade-container button:not(.comrade-dismiss) { background: #f8f9fa; border: 1px solid #a2a9b1; border-radius: 2px; padding: 2px 10px; cursor: pointer; font-weight: bold; font-size: 0.95em; margin-left: 10px; } .comrade-container button:not(.comrade-dismiss):hover { border-color: #36c; color: #36c; background: #fff; } .comrade-dismiss { background: transparent; border: none; color: #d33; font-weight: bold; cursor: pointer; font-size: 0.9em; } .comrade-dismiss:hover { text-decoration: underline; } .comrade-code-block { background: #f1f1f1; padding: 4px 8px; border-radius: 3px; font-family: monospace; display: inline-block; margin-top: 4px; } `); function appendDismiss($el) { $('<button>').addClass('comrade-dismiss').text('Dismiss').click(function() { $(this).closest('.comrade-container').fadeOut(); }).appendTo($el.find('.comrade-header')); $("#siteSub").after($el); } async function checkAndRenderRedirect(redirTitle, targetTitle, rCategory, labelText, customWikitext) { const api = new mw.Api(); const res = await api.get({ action: 'query', titles: redirTitle, formatversion: 2 }); if (res.query.pages[0].missing) { const safeId = "comrade-redir-" + btoa(unescape(encodeURIComponent(redirTitle))).replace(/=/g, ""); const $container = $('<div>').addClass('comrade-container comrade-info').attr('id', safeId); const $header = $('<div>').addClass('comrade-header'); const summary = `Created redirect from ${labelText.toLowerCase()} to [[${targetTitle}]]`; const $btn = $('<button>').text('Create redirect').click(() => createModernRedirect(redirTitle, targetTitle, rCategory, summary, safeId, customWikitext)); $header.append($('<div>').append($('<strong>').text(`${labelText}: `), `Create redirect from `, $('<code>').text(redirTitle), $btn)); $container.append($header); appendDismiss($container); } } async function checkDomainRedirect(qid, currentTitle) { let domainCandidate = ""; if (qid) { try { const res = await $.ajax({ url: "https://www.wikidata.org/w/api.php", data: { action: 'wbgetclaims', entity: qid, property: 'P856', format: 'json', origin: '*' } }); if (res.claims?.P856) { domainCandidate = res.claims.P856[0].mainsnak.datavalue.value; } } catch (e) { console.log("Comrade: Wikidata API call failed."); } } if (!domainCandidate) { domainCandidate = $(".infobox .url a").last().attr("href") || $(".official-website a").first().attr("href"); } if (domainCandidate) { try { const url = new URL(domainCandidate); let domain = url.hostname.replace(/^www\d*\./, ""); if (domain.includes(".") && url.pathname === "/") { const citationURL = '/api/rest_v1/data/citation/mediawiki/' + encodeURIComponent(domainCandidate); $.ajax({ url: citationURL, method: 'GET', success: function() { checkAndRenderRedirect(domain, currentTitle, "R from domain name", "Domain"); } }); } } catch (e) { console.log("Comrade: Error parsing URL object."); } } } async function checkNameList(name, type, currentTitle, hasShortDesc, isOrphan) { const api = new mw.Api(); const candidates = [`${name} (${type})`, `${name} (${type.toLowerCase()})`, `${name} (name)`, name]; const checked = new Set(); for (const title of candidates) { if (checked.has(title)) continue; checked.add(title); const res = await api.get({ action: 'query', prop: 'revisions', titles: title, rvprop: 'content', formatversion: 2, redirects: 0 }); const page = res.query.pages[0]; if (page && !page.missing) { const text = page.revisions[0].content; const resolvedTitle = page.title; const isNameMatch = /\{\{(Surname|Hndis|Given[ _]name|Forename|Givenname)/i.test(text); const isNameDab = /\{\{(Disambiguation|Dab|Disambig)(?:[^}]*\|(surname|surnames|given[ _]name|given[ _]names)|(?:\s*\}\}))/i.test(text); if (isNameMatch || isNameDab) { const escapedTitle = currentTitle.replace(/[.*+?^${}()|[\]\\]/g, '\\$&').replace(/ /g, '[ _]'); const alreadyListed = new RegExp('(\\[\\[|\\{\\{anbl\\|[ _]*|\\|)' + escapedTitle, 'i').test(text); if (alreadyListed) break; const $container = $('<div>').addClass('comrade-container'); const $header = $('<div>').addClass('comrade-header'); const $content = $('<div>').addClass('comrade-content'); if (isOrphan) { $container.addClass('comrade-nudge'); $header.append($('<strong>').text('Comrade nudge:')); } else { $container.addClass('comrade-info'); $header.append($('<strong>').text('Informative:')); } $content.append($('<span>').append(`${type.charAt(0).toUpperCase() + type.slice(1)} not listed at `, $('<a>').attr({ href: mw.util.getUrl(resolvedTitle), target: '_blank' }).text(resolvedTitle), "; should it be?")); const snippet = '* {{anbl|' + currentTitle + '}}'; const $snippetWrapper = $('<div>').css({ 'display': 'flex', 'align-items': 'center', 'gap': '10px', 'margin-top': '4px' }); const $instructionSpan = $('<span>').append('If the Short description is good, consider adding ', $('<code>').text(snippet).css({ 'background-color': '#f8f9fa', 'border': '1px solid #eaecf0', 'border-radius': '2px', 'padding': '1px 4px' })); const $copyBtn = $('<button>').text('Copy').css('margin-left', '0').click(function() { navigator.clipboard.writeText(snippet).then(() => { const $this = $(this); const originalText = $this.text(); $this.text('Copied!').prop('disabled', true); setTimeout(() => { $this.text(originalText).prop('disabled', false); }, 1500); }); }); $snippetWrapper.append($instructionSpan, $copyBtn); $content.append($snippetWrapper); if (!hasShortDesc) { $content.append($('<span>').css({ 'color': '#d33', 'font-weight': 'bold', 'margin-top': '5px' }).text('⚠️ Missing short description: Please add a concise one before listing.')); } $container.append($header, $content); appendDismiss($container); break; } } } } async function createModernRedirect(redirTitle, targetTitle, rCategory, customSummary, elementId, customWikitext) { const api = new mw.Api(); const content = customWikitext || `#REDIRECT [[${targetTitle}]]\n\n{{Redirect category shell|\n{{${rCategory}}}\n}}`; const summary = customSummary || `Created redirect from [[${redirTitle}]]`; return api.postWithToken('csrf', { action: 'edit', title: redirTitle, text: content, summary: summary, createonly: true }).done(() => { mw.notify("Redirect created!", { type: 'success', tag: 'comrade', classes: ['comrade-success'] }); $(`#${elementId}`).fadeOut(); }); } function getSmartSortKey(fullName, entity) { const countryIds = entity.claims?.P27?.map(c => c.mainsnak?.datavalue?.value?.id) || []; const locationIds = entity.claims?.P17?.map(c => c.mainsnak?.datavalue?.value?.id) || []; const placeIds = [...(entity.claims?.P19 || []), ...(entity.claims?.P119 || [])].map(c => c.mainsnak?.datavalue?.value?.id).filter(Boolean); const allRelevantIds = [...countryIds, ...locationIds, ...placeIds]; const birthYear = parseInt(entity.claims?.P569?.[0]?.mainsnak?.datavalue?.value?.time?.match(/[+-](\d{4})/)?.[1]) || 2026; if (fullName.startsWith("Saint ")) return fullName.replace("Saint ", ""); const arabicParticles = /\b(Abu|Abd|Abdel|Abdul|ben|bin|bint)\b/i; if (fullName.match(arabicParticles)) { if (birthYear > 1900) { const parts = fullName.split(' '); const binIndex = parts.findIndex(p => p.toLowerCase() === 'bin' || p.toLowerCase() === 'ben'); if (binIndex > 0) return parts.slice(binIndex).join(' ') + ', ' + parts.slice(0, binIndex).join(' '); } else { return fullName; } } const eastAsianQids = ["Q148", "Q184", "Q884", "Q424", "Q881", "Q17"]; if (allRelevantIds.some(id => eastAsianQids.includes(id))) { if (allRelevantIds.includes("Q17") && birthYear > 1885) return westernSort(fullName); const parts = fullName.split(' '); if (parts.length > 1) return `${parts[0]}, ${parts.slice(1).join(' ')}`; } return westernSort(fullName); } function westernSort(name) { let cleanName = name; if (name.startsWith("O'")) cleanName = name.replace("O'", "O"); const parts = cleanName.split(' '); if (parts.length < 2) return cleanName; const surname = parts.pop(); if (["Jr.", "Jr", "III", "II", "Sr.", "Sr"].includes(surname)) { const actualSurname = parts.pop(); return `${actualSurname}, ${parts.join(' ')} ${surname}`; } return `${surname}, ${parts.join(' ')}`; } async function performDeorphan() { const api = new mw.Api(); await api.edit(mw.config.get('wgPageName'), function(rev) { let text = rev.content; const summary = 'Article has backlinks; removed [[Template:Orphan|{{Orphan}}]]'; text = text.replace(/\{\{Orphan\s*(?:\|[^}]*)?\}\}\s*/gi, ''); text = text.replace(/(\{\{Multiple[ _]issues\s*)\|\s*\|/gi, '$1|'); text = replaceMI(text); text = text.replace(/\n{3,}/g, '\n\n').trim(); return { text, summary, minor: true }; }); mw.notify('Orphan tag removed!', { type: 'success', tag: 'comrade', classes: ['comrade-success'] }); setTimeout(() => location.reload(), 700); } function replaceMI(text) { const miStart = /\{\{Multiple[ _]issues\s*\|/gi; let result = ''; let lastIndex = 0; let match; while ((match = miStart.exec(text)) !== null) { const start = match.index; result += text.slice(lastIndex, start); let depth = 0; let i = start; while (i < text.length) { if (text[i] === '{' && text[i + 1] === '{') { depth++; i += 2; } else if (text[i] === '}' && text[i + 1] === '}') { depth--; i += 2; if (depth === 0) break; } else { i++; } } const end = i; const full = text.slice(start, end); const pipeIdx = full.indexOf('|'); const inner = full.slice(pipeIdx + 1, full.length - 2).trim(); const topLevel = extractTopLevelTemplates(inner); if (topLevel.length === 0) { result += ''; } else if (topLevel.length === 1) { result += topLevel[0].trim(); } else { result += full; } lastIndex = end; miStart.lastIndex = lastIndex; } result += text.slice(lastIndex); return result; } function extractTopLevelTemplates(inner) { const templates = []; let i = 0; while (i < inner.length) { if (inner[i] === '{' && inner[i + 1] === '{') { let depth = 0; const start = i; while (i < inner.length) { if (inner[i] === '{' && inner[i + 1] === '{') { depth++; i += 2; } else if (inner[i] === '}' && inner[i + 1] === '}') { depth--; i += 2; if (depth === 0) break; } else { i++; } } templates.push(inner.slice(start, i)); } else { i++; } } return templates; } async function performSortCorrection(newName, type) { const api = new mw.Api(); const title = mw.config.get("wgPageName"); try { const data = await api.get({ action: 'query', prop: 'revisions', titles: title, rvprop: 'content', formatversion: 2 }); let content = data.query.pages[0].revisions[0].content; const dsRegex = /\{\{(?:DEFAULTSORT|Defaultsort):[^}]+\}\}/i; const newTag = `{{DEFAULTSORT:${newName}}}`; let actionDesc = type === "add" ? "added" : "corrected"; if (dsRegex.test(content)) { content = content.replace(dsRegex, newTag); } else { const catRegex = /\[\[Category:/i; if (catRegex.test(content)) { content = content.replace(catRegex, `${newTag}\n[[Category:`); } else { content += `\n\n${newTag}`; } } await api.postWithToken('csrf', { action: 'edit', title: title, text: content, summary: `Setting DEFAULTSORT to ${newName}`, nocreate: true }); mw.notify(`DEFAULTSORT ${actionDesc} to ${newName}!`, { title: 'Comrade Success', type: 'success' }); setTimeout(() => location.reload(), 700); } catch (err) { mw.notify('Failed to save DEFAULTSORT.', { type: 'error' }); } } function stripDiacritics(str) { return str.normalize("NFD").replace(/[\u0300-\u036f]/g, ""); } function renderSortNudge(target, reason) { const $dsNudge = $('<div>').addClass('comrade-container comrade-nudge'); const $header = $('<div>').addClass('comrade-header'); const $btn = $('<button>').text(`Correct to: ${target}`).click(() => performSortCorrection(target, "format")); $header.append($('<div>').append($('<strong>').text('DEFAULTSORT:'), ` ${reason} `, $btn)); $dsNudge.append($header); appendDismiss($dsNudge); } async function fetchWikidataNameLabels(entity) { const familyIds = entity.claims?.P734?.map(c => c.mainsnak.datavalue.value.id) || []; const givenIds = entity.claims?.P735?.map(c => c.mainsnak.datavalue.value.id) || []; const allNameIds = [...new Set([...familyIds, ...givenIds])]; if (allNameIds.length === 0) return { givens: [], surnames: [] }; const nameData = await $.ajax({ url: "https://www.wikidata.org/w/api.php", data: { action: 'wbgetentities', ids: allNameIds.join('|'), props: 'labels', languages: 'en', format: 'json', origin: '*' }, dataType: 'json' }); return { givens: givenIds.map(id => nameData.entities[id]?.labels?.en?.value).filter(Boolean), surnames: familyIds.map(id => nameData.entities[id]?.labels?.en?.value).filter(Boolean) }; } function fixNameCasing(part, referenceName) { return part.split(' ').map(word => { const match = referenceName.match(new RegExp(`\\b${word}\\b`, 'i')); if (match) return match[0]; return referenceName.split(' ').find(tWord => word.toLowerCase().startsWith(tWord.toLowerCase()) || tWord.toLowerCase().startsWith(word.toLowerCase())) || word; }).join(' '); } function getLongNameFromWikitext(wikitext) { const firstLine = wikitext.split('\n').find(l => l.includes("'''")); if (!firstLine) return null; const boldMatch = firstLine.match(/'''(.+?)'''/); if (!boldMatch) return null; return boldMatch[1].replace(/\s*([“"«《„‹「『'].+?[”"»》”›」』']|\([^)\n]*\))\s*/g, ' ').replace(/\s+/g, ' ').trim(); } if (mw.config.get("wgDBname") === "enwiki" && mw.config.get("wgUserId") === 19244234 && mw.config.get("wgNamespaceNumber") === 0 && mw.config.get("wgAction") === "view") { $(document).ready(async function() { const api = new mw.Api(); const qid = mw.config.get("wgWikibaseItemId"); try { const [pageData, backlinkData] = await Promise.all([ api.get({ action: 'query', prop: 'revisions', titles: mw.config.get("wgPageName"), rvprop: 'content', formatversion: 2 }), api.get({ action: 'query', list: 'backlinks', blfilterredir: 'nonredirects', bllimit: 50, blnamespace: 0, bltitle: mw.config.get("wgPageName"), formatversion: 2 }) ]); const page = pageData.query.pages[0]; if (!page || page.missing || !page.revisions) return; const wikitext = page.revisions[0].content; const currentTitle = mw.config.get("wgTitle"); const cleanTitle = stripDiacritics(currentTitle); const isOrphanTagged = /\{\{\s*(Orphan|Do-attempt|Lonely|Orp|Orphaned article)/i.test(wikitext) || /\| *orphan *=/i.test(wikitext); const backLinkCount = backlinkData.query.backlinks.length; if (isOrphanTagged && backLinkCount >= 1) { const $container = $('<div>').addClass('comrade-container comrade-status'); const $header = $('<div>').addClass('comrade-header'); const $btn = $('<button>').text('Remove orphan tag').click(() => performDeorphan()); $header.append($('<div>').append($('<strong>').text('Status:'), ` Article has ${backLinkCount} backlink(s).`, $btn)); $container.append($header); appendDismiss($container); } if (cleanTitle !== currentTitle) checkAndRenderRedirect(cleanTitle, currentTitle, "R to diacritic", "Diacritic"); checkDomainRedirect(qid, currentTitle); if (qid) { const wikiData = await $.ajax({ url: "https://www.wikidata.org/w/api.php", data: { action: 'wbgetentities', ids: qid, props: 'claims|labels', languages: 'en', format: 'json', origin: '*' }, dataType: 'json' }); const entity = wikiData.entities[qid]; const isHuman = entity?.claims?.P31?.some(c => c.mainsnak?.datavalue?.value?.id === "Q5"); const tClean = currentTitle.replace(/\s*\(.*?\)\s*/g, '').trim(); const nameParts = tClean.split(' '); const hasFamilyNameHatnote = /\{\{family[ _]name[ _]hatnote/i.test(wikitext); const hasShortDesc = /\{\{\s*[Ss]hort description/i.test(wikitext); const dsMatch = wikitext.match(/\{\{(?:DEFAULTSORT|Defaultsort):([^}]+)\}\}/i); const isOrphan = isOrphanTagged && backLinkCount < 1; const primarySurname = hasFamilyNameHatnote ? nameParts[0] : (getSmartSortKey(tClean, entity).split(',')[0] || nameParts[nameParts.length - 1]); let targetSortName = ""; if (isHuman) { const { givens, surnames } = await fetchWikidataNameLabels(entity); const refName = entity.labels?.en?.value || currentTitle; if (dsMatch) { const currentDS = dsMatch[1].trim(); targetSortName = currentDS; if (currentDS.includes(',')) { let [lastPart, firstPart] = currentDS.split(',').map(s => s.trim()); if (firstPart.toLowerCase().endsWith(lastPart.toLowerCase())) { firstPart = firstPart.substring(0, firstPart.length - lastPart.length).trim(); targetSortName = `${fixNameCasing(lastPart, refName)}, ${fixNameCasing(firstPart, refName)}`; renderSortNudge(targetSortName, "Redundant surname in given name field."); } else if (givens.length > 0 && lastPart.split(' ').length > 1) { const misplacedGiven = lastPart.split(' ').find(part => givens.some(gn => gn.toLowerCase() === part.toLowerCase())); if (misplacedGiven) { const newSurname = lastPart.split(' ').filter(p => p !== misplacedGiven).join(' '); targetSortName = `${fixNameCasing(newSurname, refName)}, ${fixNameCasing(misplacedGiven + ' ' + firstPart, refName)}`; renderSortNudge(targetSortName, `Wikidata suggests "${misplacedGiven}" is a given name.`); } } } } else { targetSortName = hasFamilyNameHatnote ? `${nameParts[0]}, ${nameParts.slice(1).join(' ')}` : getSmartSortKey(tClean, entity); const $dsMissing = $('<div>').addClass('comrade-container comrade-nudge'); const $header = $('<div>').addClass('comrade-header'); const $btn = $('<button>').text(`Add: {{DEFAULTSORT:${targetSortName}}}`).click(() => performSortCorrection(targetSortName, "add")); $header.append($('<div>').append($('<strong>').text('DEFAULTSORT:'), ` Tag is missing. `, $btn)); $dsMissing.append($header); appendDismiss($dsMissing); } const longName = getLongNameFromWikitext(wikitext); if (longName && longName.length > tClean.length) { let sortKey = hasFamilyNameHatnote ? `${longName.split(' ')[0]}, ${longName.split(' ').slice(1).join(' ')}` : getSmartSortKey(longName, entity); const rLongWikitext = `#REDIRECT [[${currentTitle}]]\n\n{{Redirect category shell|\n{{R from long name}}\n}}\n{{DEFAULTSORT:${sortKey}}}`; checkAndRenderRedirect(longName, currentTitle, null, "Long name", rLongWikitext); } if (targetSortName) { let targetPage = currentTitle.includes(' (') ? currentTitle.split(' (')[0] : currentTitle; let rCat = targetPage !== currentTitle ? "R from ambiguous sort name" : "R from sort name"; if (targetSortName.includes(',')) { const p = targetSortName.split(','); rCat += `|${p[0].trim().charAt(0).toUpperCase()}|${p[1].trim().charAt(0).toUpperCase()}`; } checkAndRenderRedirect(targetSortName, targetPage, rCat, "Sort name"); } const finalFamilyNames = new Set(); const finalGivenNames = new Set(); surnames.forEach(fn => { if (tClean.toLowerCase().includes(fn.toLowerCase())) { fn.split(' ').forEach(part => finalFamilyNames.add(part)); finalFamilyNames.add(fn); } }); givens.forEach(gn => { if (tClean.toLowerCase().includes(gn.toLowerCase())) finalGivenNames.add(gn); }); if (finalFamilyNames.size === 0 && nameParts.length >= 2) finalFamilyNames.add(nameParts[nameParts.length - 1]); if (finalGivenNames.size === 0 && nameParts.length >= 2) finalGivenNames.add(nameParts[0]); const getPriorityTarget = async (name, type) => { const titles = type === 'surname' ? [`List of people with surname ${name}`, `List of people with the English surname ${name}`, `${name} (surname)`] : [`List of people with given name ${name}`, `${name} (given name)`]; const res = await api.get({ action: 'query', titles: titles.join('|'), formatversion: 2 }); return titles.find(t => res.query.pages.find(pg => pg.title === t && !pg.missing)); }; for (const name of finalGivenNames) { if (name.toLowerCase() === primarySurname.toLowerCase()) continue; const target = await getPriorityTarget(name, 'given'); if (target) await checkNameList(name, 'given name', currentTitle, hasShortDesc, isOrphan, target); } for (const name of finalFamilyNames) { const target = await getPriorityTarget(name, 'surname'); if (target) await checkNameList(name, 'surname', currentTitle, hasShortDesc, isOrphan, target); } } } } catch (err) { console.error("Comrade error:", err); } }); } })(); (function() { if (window.IllWill) return; const STRIKEOUT = true; const HIDE = 'hide'; const IllWill = { Version: "1.1.1", Attribution: 'created by <a target="_blank" href="/wiki/User:Cobaltcigs">cobaltcigs</a>', Summary: "Added interlanguage links using IllWill.js", DataApi: "https://www.wikidata.org/w/api.php", LocalLang: mw.config.get("wgPageContentLanguage"), Disambiguator: / \(.*\)$/, SiteLinks: {}, Config: { MaxLanguages: 5, IgnoreScientific: STRIKEOUT, AutoDiff: true }, css: ` #illwill { clear: both; margin-bottom: 1.5em; border: 1px solid #a2a9b1; padding: 15px; background: #f8f9fa; box-shadow: 0 2px 4px rgba(0,0,0,0.1); } .ill-sitelinks a { display: inline-block; margin-bottom: 3px; font-size: 0.9em; color: #36c; } .ill-size-tag { font-size: 0.8em; color: #72777d; margin-left: 6px; white-space: nowrap; } .illwill-ignore { text-decoration: line-through; color: #72777d; font-size: 0.85em; } .ill-x { width: 35px; text-align: center; } .ill-input, .ill-output { font-family: 'Courier New', monospace; white-space: pre-wrap; font-size: 0.9em; background: #fff; border: 1px solid #eaecf0; padding: 4px; border-radius: 2px; } #ill-buttons { text-align: right; padding: 10px; border-top: 1px solid #a2a9b1; margin-top: 10px; } #ill-buttons button { margin-left: 10px; cursor: pointer; padding: 6px 16px; border-radius: 2px; border: 1px solid #a2a9b1; transition: all 0.2s; } #ill-ok { background: #36c; color: #fff; border-color: #36c !important; font-weight: bold; } #ill-ok:hover { background: #447ff5; } #ill-ok:disabled { background: #eaecf0; color: #72777d; border-color: #c8ccd1 !important; cursor: not-allowed; opacity: 0.7; } #ill-table { width: 100%; border-collapse: collapse; margin-top: 10px; background: white; } #ill-table th { background: #f2f2f2; text-align: left; padding: 8px; border: 1px solid #a2a9b1; } #ill-table td { padding: 8px; border: 1px solid #a2a9b1; vertical-align: top; } #ill-table caption { background: #eaffea; font-weight: bold; padding: 10px; border: 1px solid #a2a9b1; border-bottom: none; font-size: 1.1em; } #ill-help { font-size: 0.85em; color: #54595d; padding: 10px; line-height: 1.4; } .ill-loading-inline { font-style: italic; color: #72777d; font-size: 0.9em; display: block; margin: 5px 0; } `, setup() { if (!["edit", "submit"].includes(mw.config.get('wgAction'))) return; mw.loader.addStyleTag(this.css); const link = mw.util.addPortletLink('p-cactions', '#', 'IllWill', 'ca-illwill', "Add interlanguage links via Wikidata"); if (link) { link.addEventListener('click', (e) => { e.preventDefault(); this.makePanel(); }); } }, norm(s) { if (!s) return ""; const t = s.trim().replace(/[\s_]+/g, " "); return t.charAt(0).toUpperCase() + t.slice(1); }, async getRedLinks($textbox) { const txt = $textbox.textSelection('getContents') || ""; const wl = txt.match(/\[\[[^[\]\n]+\]\]/g); if (!wl) return { reds: [], txt }; const api = new mw.Api(); const textToParse = wl.join("").replace(/\|[^\]]+/g, ""); try { const data = await api.post({ action: 'parse', text: textToParse, contentmodel: 'wikitext', formatversion: 2 }); const tempDiv = document.createElement('div'); tempDiv.innerHTML = data.parse.text; const reds = Array.from(tempDiv.querySelectorAll("a.new")).map(x => { const urlParams = new URLSearchParams(x.href.split('?')[1]); return urlParams.get('title')?.replace(/_/g, " "); }).filter(Boolean); return { reds: [...new Set(reds)], txt }; } catch (e) { return { reds: [], txt }; } }, async makePanel() { const $editform = $('#editform'); const $textbox = $('#wpTextbox1'); $('#illwill').remove(); $editform.hide(); const $wrapper = $('<div id="illwill">Loading redlinks...</div>').insertBefore($editform); const { reds, txt } = await this.getRedLinks($textbox); const wtLinks = []; reds.forEach(title => { const escaped = title.replace(/[.*+?^${}()|[\]\\]/g, '\\$&').replace(/\s/g, "[\\s_]+"); const re = new RegExp("\\[\\[\\s*" + escaped + "\\s*(?:\\|[^\\[\\]]+)?\\]\\]", "ig"); const match = txt.match(re); if (match && !wtLinks.some(z => z.title === title)) { wtLinks.push({ link: match[0], title }); } }); if (!wtLinks.length) { const $back = $('<button>Quit</button>').on('click', () => { $wrapper.remove(); $editform.show(); }); $wrapper.empty().append($('<strong>No valid redlinks found in text.</strong> '), $back); return; } const $table = $(` <table id="ill-table" class="wikitable"> <caption>IllWill.js (v${this.Version})</caption> <thead> <tr> <th class="ill-x"><input type="checkbox" id="ill-select-all" disabled></th> <th>Input link</th> <th>Possible Wikidata matches</th> <th>Sitelinks (top ${this.Config.MaxLanguages} by size)</th> <th>Resulting wikitext</th> </tr> </thead> <tbody></tbody> <tfoot> <tr> <td colspan="3" id="ill-help">Carefully examine possible Wikidata matches.</td> <td colspan="2" id="ill-buttons"> <button id="ill-cancel">Cancel</button> <button id="ill-ok" disabled>Show changes</button> </td> </tr> </tfoot> </table> `); const $tbody = $table.find('tbody'); wtLinks.forEach((item, i) => { $tbody.append(` <tr id="ill-row-${i}" data-index="${i}"> <td class="ill-x"><input type="checkbox" class="ill-row-check" disabled></td> <td class="ill-input">${this.escapeHTML(item.link)}</td> <td class="ill-wd-item"><span class="ill-loading-inline">Searching...</span></td> <td class="ill-sitelinks"></td> <td class="ill-output"></td> </tr> `); }); $wrapper.empty().append($table); const chunkSize = 5; for (let i = 0; i < wtLinks.length; i += chunkSize) { const chunk = wtLinks.slice(i, i + chunkSize); await Promise.all(chunk.map((item, idx) => this.fetchWikidataOptimized(item.title, i + idx))); } $table.on('click', '#ill-cancel', () => { $editform.show(); $wrapper.remove(); }); $table.on('click', '#ill-ok', () => this.onOkButton($editform, $wrapper, $textbox)); $table.on('change', '#ill-select-all', (e) => { const isChecked = $(e.target).is(':checked'); $table.find('.ill-row-check:not(:disabled)').each(function() { $(this).prop('checked', isChecked).trigger('change'); }); }); $table.on('change', '.ill-row-check', (e) => { this.onCheckbox(e); this.updateOkButtonState($table); }); $table.on('change', 'input[type="radio"]', (e) => { this.showSiteLinks(e); }); }, async fetchWikidataOptimized(title, index) { const query = title.replace(this.Disambiguator, ""); const url = `${this.DataApi}?action=wbsearchentities&search=${encodeURIComponent(query)}&language=${this.LocalLang}&limit=5&format=json&origin=*`; try { const resp = await fetch(url); const data = await resp.json(); const results = data.search; const $cell = $(`#ill-row-${index} .ill-wd-item`); if (!results || !results.length) { $cell.html('<span class="ill-na">(no results)</span>'); return; } const entityIds = results.map(r => r.id); await this.fetchEntities(entityIds, index, $cell); } catch (e) { $(`#ill-row-${index} .ill-wd-item`).text("Search failed."); } }, async fetchEntities(ids, rowIndex, $cell) { const url = `${this.DataApi}?action=wbgetentities&ids=${ids.join('|')}&props=labels|descriptions|claims|sitelinks&format=json&origin=*`; try { const resp = await fetch(url); const data = await resp.json(); $cell.empty(); ids.forEach(qNum => { const entity = data.entities[qNum]; if (!entity) return; const isScientific = entity.claims?.P31?.some(s => s.mainsnak?.datavalue?.value?.id === "Q13442814"); if (isScientific && this.Config.IgnoreScientific === HIDE) return; const desc = entity.descriptions?.[this.LocalLang]?.value || entity.descriptions?.en?.value || ""; const label = entity.labels?.[this.LocalLang]?.value || entity.labels?.en?.value || qNum; const isStrikeout = isScientific && this.Config.IgnoreScientific === STRIKEOUT; const $div = $(` <div class="${isStrikeout ? 'illwill-ignore' : ''}"> <input type="radio" name="selection-${rowIndex}" value="${qNum}" id="radio-${qNum}" ${isStrikeout ? 'disabled' : ''}> <label for="radio-${qNum}"> <a href="https://wikidata.org/wiki/${qNum}" target="_blank">${this.escapeHTML(label)}</a>: <span class="ill-desc">${desc ? this.escapeHTML(desc) : '<i>no description</i>'}</span> </label> </div> `); $cell.append($div); this.SiteLinks[qNum] = entity.sitelinks || {}; }); } catch (e) { $cell.text("Detail fetch failed."); } }, updateOkButtonState($table) { const $rows = $table.find('.ill-row-check:not(:disabled)'); const $checkedRows = $rows.filter(':checked'); const anyEnabled = $rows.length > 0; $table.find('#ill-ok').prop('disabled', $checkedRows.length === 0); const $master = $table.find('#ill-select-all'); $master.prop('disabled', !anyEnabled); if (anyEnabled && $rows.length === $checkedRows.length) { $master.prop('checked', true); } else { $master.prop('checked', false); } }, async showSiteLinks(e) { const isManualToggling = e.fromCheckbox || false; const qNum = e.target.value; const $row = $(e.target).closest('tr'); const sitelinks = this.SiteLinks[qNum]; const $checkbox = $row.find('.ill-row-check'); const $sitelinkCell = $row.find('.ill-sitelinks'); const $outputCell = $row.find('.ill-output'); const $table = $('#ill-table'); const effectiveMax = Math.min(Math.max(this.Config.MaxLanguages, 3), 6); const validKeys = Object.keys(sitelinks).filter(k => k.endsWith('wiki') && !k.includes('commons')); $sitelinkCell.html('<span class="ill-loading-inline">Measuring articles...</span>'); $outputCell.empty(); if (!isManualToggling) { $checkbox.prop('disabled', true).prop('checked', false); } const candidates = validKeys.slice(0, 25); const sizeMap = []; await Promise.all(candidates.map(async (key) => { const lang = key.replace('wiki', '').replace(/_/g, '-'); const title = sitelinks[key].title; const endpoint = `https://${lang}.wikipedia.org/w/api.php?action=query&titles=${encodeURIComponent(title)}&prop=info&format=json&origin=*`; try { const res = await fetch(endpoint).then(r => r.json()); const page = Object.values(res.query.pages)[0]; sizeMap.push({ lang, title, length: page.length || 0 }); } catch (err) { sizeMap.push({ lang, title, length: 0 }); } })); sizeMap.sort((a, b) => b.length - a.length); const topLinks = sizeMap.slice(0, effectiveMax); $sitelinkCell.html(topLinks.map(item => { const kbValue = Math.round(item.length / 1024); return `<div><a href="https://${item.lang}.wikipedia.org/wiki/${encodeURIComponent(item.title)}" target="_blank">${item.lang}:${this.escapeHTML(item.title)}</a> <span class="ill-size-tag">(${kbValue} kB)</span></div>`; }).join("")); const inputWikitext = $row.find('.ill-input').text(); const match = inputWikitext.match(/\[\[(.*?)\]\]/); if (match) { const parts = match[1].split('|'); const targetPage = parts[0].trim(); const surfaceName = (parts[1] || parts[0]).trim(); const illLangs = topLinks.map(item => { const isSameTitle = this.norm(item.title) === this.norm(targetPage); return `|${item.lang}|${isSameTitle ? '' : item.title}`; }).join(""); const ltParam = (this.norm(surfaceName) === this.norm(targetPage)) ? "" : `|lt=${surfaceName}`; $outputCell.text(`{{ill|${targetPage}${ltParam}${illLangs}}}`); } $checkbox.prop('disabled', !topLinks.length); if (!isManualToggling) { $checkbox.prop('checked', !!topLinks.length); } this.updateOkButtonState($table); }, onCheckbox(e) { const $row = $(e.target).closest('tr'); const $radio = $row.find('input[type="radio"]:checked'); const isChecked = $(e.target).is(':checked'); if (isChecked) { if ($radio.length) { this.showSiteLinks({ target: $radio[0], fromCheckbox: true }); } } else { $row.find('.ill-sitelinks, .ill-output').empty(); } }, onOkButton($editform, $wrapper, $textbox) { let text = $textbox.textSelection('getContents'); let changed = false; $wrapper.find('.ill-row-check:checked').each(function() { const $row = $(this).closest('tr'); const input = $row.find('.ill-input').text(); const output = $row.find('.ill-output').text(); if (output) { const escapedInput = input.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); text = text.replace(new RegExp(escapedInput, "gi"), output); changed = true; } }); if (changed) { $('#wpSummary').val((i, v) => (v ? v + "; " : "") + this.Summary); $textbox.textSelection('setContents', text); $wrapper.remove(); $editform.show(); if (this.Config.AutoDiff) $('#wpDiff').click(); } }, escapeHTML(str) { return str.replace(/[&<>"']/g, m => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' })[m]); } }; window.IllWill = IllWill; mw.loader.using(['mediawiki.util', 'mediawiki.api', 'jquery.textSelection'], () => { $(() => IllWill.setup()); }); })(); //</nowiki> 47615lh2wxm2gsj6moulss9595uhub1 739071 739070 2026-04-22T06:19:55Z Sam Sailor 26820 Test 739071 javascript text/javascript //<nowiki> window.headmaster_auto_run = true; (function() { if (window.Headmaster) return; const defaultNS = [0, 2, 10, 118]; const userNS = window.headmaster_ns || []; const config = { menu: window.headmaster_menu || 'p-cactions', enableSummary: window.headmaster_do_summary !== false, customSummary: window.headmaster_summary || "", allowedNamespaces: Array.from(new Set([...defaultNS, ...userNS])), autoScan: window.headmaster_auto_scan !== false, autoRun: window.headmaster_auto_run === true }; const Headmaster = { VERSION: "0.9.1", DefaultSummary: "Converting [[MOS:PSEUDOHEAD|pseudo-headings]] {details}using [[User:Sam_Sailor/Scripts/Headmaster.js|Headmaster]]. Semicolon markup is reserved for [[MOS:DLIST|description lists]].", styleInjected: false, css: ` #hm-panel { clear: both; border: 1px solid #a2a9b1; padding: 15px; background: #f8f9fa; margin-bottom: 1.5em; border-radius: 2px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); } #hm-table { width: 100%; border-collapse: collapse; background: white; margin-top: 10px; } #hm-table th { background: #f2f2f2; border: 1px solid #a2a9b1; padding: 8px; text-align: left; } #hm-table td { border: 1px solid #a2a9b1; padding: 8px; vertical-align: middle; } .hm-context { font-family: 'Courier New', monospace; font-size: 0.9em; color: #54595d; background: #fdfdfd; } #hm-controls { display: flex; justify-content: space-between; align-items: center; margin-top: 15px; } #hm-controls button { margin-left: 10px; padding: 6px 16px; cursor: pointer; border-radius: 2px; } .hm-btn-apply { background: #36c; color: white; border: 1px solid #36c; font-weight: bold; } .hm-btn-apply:hover { background: #447ff5; } .hm-global-selector { font-size: 0.9em; color: #202122; background: #eaecf0; padding: 8px; border-radius: 2px; border: 1px solid #a2a9b1; } .hm-global-selector a { font-weight: bold; text-decoration: none; color: #36c; } .hm-global-selector a:hover { text-decoration: underline; } .hm-locate-btn { cursor: pointer; color: #36c; border: 1px solid #a2a9b1; background: #f8f9fa; padding: 2px 6px; font-size: 0.85em; border-radius: 2px; } .hm-locate-btn:hover { background: #fff; border-color: #36c; } `, setup() { if (!config.allowedNamespaces.includes(mw.config.get("wgNamespaceNumber"))) return; const action = mw.config.get("wgAction"); this.addPortlet(action); if (action === 'view' && (config.autoScan || config.autoRun)) { this.silentScan(); } if (mw.util.getParamValue('headmaster') === '1' && ['edit', 'submit'].includes(action)) { const params = new URLSearchParams(window.location.search); params.delete('headmaster'); const searchString = params.toString(); const newUrl = window.location.pathname + (searchString ? '?' + searchString : ''); window.history.replaceState(null, '', newUrl); this.init(); } }, addPortlet(action) { const link = mw.util.addPortletLink(config.menu, '#', 'Headmaster', 'ca-hm', 'Interactively convert pseudo-headings'); if (link) { $(link).on('click', (e) => { e.preventDefault(); if (action === 'view') { this.redirectToEdit(); } else if (['edit', 'submit'].includes(action)) { this.init(); } }); } }, redirectToEdit() { window.location.href = mw.util.getUrl(mw.config.get("wgPageName"), { action: 'edit', headmaster: '1' }); }, silentScan() { new mw.Api().get({ action: 'query', prop: 'revisions', titles: mw.config.get('wgPageName'), rvprop: 'content', rvlimit: 1, formatversion: 2 }).done((data) => { const page = data.query.pages[0]; if (!page || !page.revisions) return; const wikitext = page.revisions[0].content; const tasks = this.analyzeText(wikitext); if (tasks.length > 0) { if (config.autoRun) { this.redirectToEdit(); } else { this.notifyDiscovery(tasks.length); } } }); }, notifyDiscovery(count) { const $msg = $('<span>').text(`Headmaster: Found ${count} pseudo-headings. `).append($('<a>').text('Run conversion').css({ fontWeight: 'bold', cursor: 'pointer' }).on('click', () => this.redirectToEdit())); mw.notify($msg, { tag: 'hm-discovery', autoHide: false }); }, init() { if (!this.styleInjected) { mw.loader.addStyleTag(this.css); this.styleInjected = true; } const $textbox = $('#wpTextbox1'); const wikitext = $textbox.textSelection('getContents'); if (!wikitext) { mw.notify("Textbox is empty or not found.", { type: 'error' }); return; } const tasks = this.analyzeText(wikitext); if (tasks.length === 0) { mw.notify("No pseudo-headings found."); return; } this.showUI(tasks, wikitext); }, analyzeText(wikitext) { const lines = wikitext.split("\n"); const tasks = []; let currentDepth = 2; for (let i = 0; i < lines.length; i++) { const line = lines[i].trim(); const headingMatch = line.match(/^(={2,6})\s*.+?\s*\1\s*$/); if (headingMatch) currentDepth = headingMatch[1].length; if (line.startsWith(';') && !line.startsWith(';;')) { const nextLine = lines[i + 1] || ""; if (!nextLine.trim().startsWith(':')) { const cleanText = lines[i].substring(1).replace(/\s*:.*$/, "").trim(); const suggestedLevel = "=".repeat(Math.min(currentDepth + 1, 6)); tasks.push({ index: i, original: lines[i], cleanText: cleanText, context: nextLine.substring(0, 60).trim() + (nextLine.length > 60 ? "..." : ""), suggestedLevel: suggestedLevel }); } } } return tasks; }, showUI(tasks, originalWikitext) { $('#hm-panel').remove(); $('#editform').hide(); const tableRows = tasks.map((task, i) => ` <tr data-task-index="${task.index}"> <td><button class="hm-locate-btn" data-hm-i="${i}" title="Show in editor">Locate</button></td> <td class="hm-context"><code>${mw.html.escape(task.original)}</code></td> <td><label><input type="radio" name="hm-opt-${i}" value="keep"> Keep</label></td> <td><label><input type="radio" name="hm-opt-${i}" value="bold" checked> <b>Bold</b></label></td> <td><label><input type="radio" name="hm-opt-${i}" value="head"> Heading (${task.suggestedLevel.length})</label></td> <td class="hm-context">${mw.html.escape(task.context || "(end of page)")}</td> </tr> `).join(""); const $panel = $(` <div id="hm-panel"> <h3 style="margin-top:0">Headmaster v${this.VERSION}: Review pseudo-headings</h3> <div class="hm-global-selector"> <strong>Bulk action:</strong> <a href="#" id="hm-all-keep">Set all to Keep</a> | <a href="#" id="hm-all-bold">Set all to Bold</a> | <a href="#" id="hm-all-head">Set all to Heading</a> </div> <table id="hm-table"> <thead> <tr> <th>Find</th> <th>Source</th> <th colspan="3">Action</th> <th>Next line context</th> </tr> </thead> <tbody>${tableRows}</tbody> </table> <div id="hm-controls"> <span>Found <strong>${tasks.length}</strong> possible pseudo-headings.</span> <div> <button id="hm-cancel" class="mw-ui-button">Cancel</button> <button id="hm-apply" class="hm-btn-apply">Show changes (diff)</button> </div> </div> </div> `); $('#content').prepend($panel); window.scrollTo(0, 0); $('.hm-locate-btn').on('click', function() { $(document).off('mousedown.hmlocate'); const idx = $(this).data('hm-i'); const task = tasks[idx]; const lines = originalWikitext.split('\n'); let charOffset = 0; for (let j = 0; j < task.index; j++) { charOffset += lines[j].length + 1; } $('#hm-panel').hide(); $('#editform').show(); const $textbox = $('#wpTextbox1'); $textbox.textSelection('setSelection', { start: charOffset, end: charOffset + lines[task.index].length }); $textbox.textSelection('scrollToCaretPosition'); const locateNotify = mw.notify("Locating line " + (task.index + 1) + ". Click outside the editor to return.", { tag: 'hm-locate', type: 'success', autoHide: false }); setTimeout(() => { $(document).on('mousedown.hmlocate', function(e) { if (!$(e.target).closest('#editform, .mw-notification-area').length) { $(document).off('mousedown.hmlocate'); locateNotify.then(n => n.close()); $('#editform').hide(); $('#hm-panel').show(); } }); }, 200); }); $('#hm-all-keep').on('click', (e) => { e.preventDefault(); $('input[value="keep"]').prop('checked', true); }); $('#hm-all-bold').on('click', (e) => { e.preventDefault(); $('input[value="bold"]').prop('checked', true); }); $('#hm-all-head').on('click', (e) => { e.preventDefault(); $('input[value="head"]').prop('checked', true); }); $('#hm-cancel').on('click', () => { $('#hm-panel').remove(); $('#editform').show(); }); $('#hm-apply').on('click', () => this.applyChanges(tasks, originalWikitext)); }, getProcessedSummary(existingSummary, bolds, heads) { if (!config.enableSummary) return existingSummary; let mySummary, isDefault = false; if (config.customSummary) { mySummary = config.customSummary; } else { isDefault = true; const detailsArr = []; if (bolds > 0) detailsArr.push(`${bolds} to bold`); if (heads > 0) detailsArr.push(`${heads} to heading`); const detailsStr = detailsArr.length > 0 ? `(${detailsArr.join(', ')}) ` : ""; mySummary = this.DefaultSummary.replace("{details}", detailsStr); } const trimmedOld = existingSummary.trim(); if (!trimmedOld) return mySummary; if (/[.!?]$/.test(trimmedOld)) { return trimmedOld + " " + mySummary; } else { const finalSummary = isDefault ? mySummary.charAt(0).toLowerCase() + mySummary.slice(1) : mySummary; return trimmedOld + "; " + finalSummary; } }, applyChanges(tasks, wikitext) { try { const lines = wikitext.split("\n"); let bCount = 0, hCount = 0; $('#hm-table tbody tr').each(function(i) { const action = $(this).find('input:checked').val(); const task = tasks[i]; if (action === 'bold') { lines[task.index] = `'''${task.cleanText}'''`; bCount++; } else if (action === 'head') { const h = task.suggestedLevel; lines[task.index] = `${h} ${task.cleanText} ${h}`; hCount++; } }); if (bCount + hCount === 0) { mw.notify("No changes selected."); $('#hm-panel').remove(); $('#editform').show(); return; } const $textbox = $('#wpTextbox1'); const $summary = $('#wpSummary'); $textbox.textSelection('setContents', lines.join("\n")); $summary.val(this.getProcessedSummary($summary.val(), bCount, hCount)); $('#hm-panel').remove(); $('#editform').show(); $('#wpDiff').click(); } catch (err) { $('#editform').show(); mw.notify("Headmaster error: " + err.message, { type: 'error' }); } } }; window.Headmaster = Headmaster; mw.loader.using(['mediawiki.util', 'mediawiki.api', 'jquery.textSelection'], () => { $(() => Headmaster.setup()); }); })(); (function() { var Comrade = Comrade || {}; mw.util.addCSS(` .ambox-Orphan { display: block !important; } .comrade-container { box-shadow: 0 1px 3px rgba(0,0,0,0.1); border-radius: 2px; padding: 10px 15px; margin: 10px 0; display: flex; flex-direction: column; align-items: flex-start; gap: 8px; border: 1px solid #a2a9b1; background: #fcfcfc; line-height: 1.5; } .comrade-header { display: flex; align-items: center; justify-content: space-between; width: 100%; } .comrade-content { display: flex; flex-direction: column; gap: 5px; width: 100%; } .comrade-success { background-color: #d5f5e3 !important; border-left: 5px solid #27ae60 !important; color: #1b5e20 !important; } .comrade-nudge { background: #fff9ea; border-left: 5px solid #f0ad4e; } .comrade-info { background: #eaf3ff; border-left: 5px solid #36c; } .comrade-status { background: #eaf3ff; border-left: 5px solid #36c; } .comrade-container button:not(.comrade-dismiss) { background: #f8f9fa; border: 1px solid #a2a9b1; border-radius: 2px; padding: 2px 10px; cursor: pointer; font-weight: bold; font-size: 0.95em; margin-left: 10px; } .comrade-container button:not(.comrade-dismiss):hover { border-color: #36c; color: #36c; background: #fff; } .comrade-dismiss { background: transparent; border: none; color: #d33; font-weight: bold; cursor: pointer; font-size: 0.9em; } .comrade-dismiss:hover { text-decoration: underline; } .comrade-code-block { background: #f1f1f1; padding: 4px 8px; border-radius: 3px; font-family: monospace; display: inline-block; margin-top: 4px; } `); function appendDismiss($el) { $('<button>').addClass('comrade-dismiss').text('Dismiss').click(function() { $(this).closest('.comrade-container').fadeOut(); }).appendTo($el.find('.comrade-header')); $("#siteSub").after($el); } async function checkAndRenderRedirect(redirTitle, targetTitle, rCategory, labelText, customWikitext) { const api = new mw.Api(); const res = await api.get({ action: 'query', titles: redirTitle, formatversion: 2 }); if (res.query.pages[0].missing) { const safeId = "comrade-redir-" + btoa(unescape(encodeURIComponent(redirTitle))).replace(/=/g, ""); const $container = $('<div>').addClass('comrade-container comrade-info').attr('id', safeId); const $header = $('<div>').addClass('comrade-header'); const summary = `Created redirect from ${labelText.toLowerCase()} to [[${targetTitle}]]`; const $btn = $('<button>').text('Create redirect').click(() => createModernRedirect(redirTitle, targetTitle, rCategory, summary, safeId, customWikitext)); $header.append($('<div>').append($('<strong>').text(`${labelText}: `), `Create redirect from `, $('<code>').text(redirTitle), $btn)); $container.append($header); appendDismiss($container); } } async function checkDomainRedirect(qid, currentTitle) { let domainCandidate = ""; if (qid) { try { const res = await $.ajax({ url: "https://www.wikidata.org/w/api.php", data: { action: 'wbgetclaims', entity: qid, property: 'P856', format: 'json', origin: '*' } }); if (res.claims?.P856) { domainCandidate = res.claims.P856[0].mainsnak.datavalue.value; } } catch (e) { console.log("Comrade: Wikidata API call failed."); } } if (!domainCandidate) { domainCandidate = $(".infobox .url a").last().attr("href") || $(".official-website a").first().attr("href"); } if (domainCandidate) { try { const url = new URL(domainCandidate); let domain = url.hostname.replace(/^www\d*\./, ""); if (domain.includes(".") && url.pathname === "/") { const citationURL = '/api/rest_v1/data/citation/mediawiki/' + encodeURIComponent(domainCandidate); $.ajax({ url: citationURL, method: 'GET', success: function() { checkAndRenderRedirect(domain, currentTitle, "R from domain name", "Domain"); } }); } } catch (e) { console.log("Comrade: Error parsing URL object."); } } } async function checkNameList(name, type, currentTitle, hasShortDesc, isOrphan) { const api = new mw.Api(); const candidates = [`${name} (${type})`, `${name} (${type.toLowerCase()})`, `${name} (name)`, name]; const checked = new Set(); for (const title of candidates) { if (checked.has(title)) continue; checked.add(title); const res = await api.get({ action: 'query', prop: 'revisions', titles: title, rvprop: 'content', formatversion: 2, redirects: 0 }); const page = res.query.pages[0]; if (page && !page.missing) { const text = page.revisions[0].content; const resolvedTitle = page.title; const isNameMatch = /\{\{(Surname|Hndis|Given[ _]name|Forename|Givenname)/i.test(text); const isNameDab = /\{\{(Disambiguation|Dab|Disambig)(?:[^}]*\|(surname|surnames|given[ _]name|given[ _]names)|(?:\s*\}\}))/i.test(text); if (isNameMatch || isNameDab) { const escapedTitle = currentTitle.replace(/[.*+?^${}()|[\]\\]/g, '\\$&').replace(/ /g, '[ _]'); const alreadyListed = new RegExp('(\\[\\[|\\{\\{anbl\\|[ _]*|\\|)' + escapedTitle, 'i').test(text); if (alreadyListed) break; const $container = $('<div>').addClass('comrade-container'); const $header = $('<div>').addClass('comrade-header'); const $content = $('<div>').addClass('comrade-content'); if (isOrphan) { $container.addClass('comrade-nudge'); $header.append($('<strong>').text('Comrade nudge:')); } else { $container.addClass('comrade-info'); $header.append($('<strong>').text('Informative:')); } $content.append($('<span>').append(`${type.charAt(0).toUpperCase() + type.slice(1)} not listed at `, $('<a>').attr({ href: mw.util.getUrl(resolvedTitle), target: '_blank' }).text(resolvedTitle), "; should it be?")); const snippet = '* {{anbl|' + currentTitle + '}}'; const $snippetWrapper = $('<div>').css({ 'display': 'flex', 'align-items': 'center', 'gap': '10px', 'margin-top': '4px' }); const $instructionSpan = $('<span>').append('If the Short description is good, consider adding ', $('<code>').text(snippet).css({ 'background-color': '#f8f9fa', 'border': '1px solid #eaecf0', 'border-radius': '2px', 'padding': '1px 4px' })); const $copyBtn = $('<button>').text('Copy').css('margin-left', '0').click(function() { navigator.clipboard.writeText(snippet).then(() => { const $this = $(this); const originalText = $this.text(); $this.text('Copied!').prop('disabled', true); setTimeout(() => { $this.text(originalText).prop('disabled', false); }, 1500); }); }); $snippetWrapper.append($instructionSpan, $copyBtn); $content.append($snippetWrapper); if (!hasShortDesc) { $content.append($('<span>').css({ 'color': '#d33', 'font-weight': 'bold', 'margin-top': '5px' }).text('⚠️ Missing short description: Please add a concise one before listing.')); } $container.append($header, $content); appendDismiss($container); break; } } } } async function createModernRedirect(redirTitle, targetTitle, rCategory, customSummary, elementId, customWikitext) { const api = new mw.Api(); const content = customWikitext || `#REDIRECT [[${targetTitle}]]\n\n{{Redirect category shell|\n{{${rCategory}}}\n}}`; const summary = customSummary || `Created redirect from [[${redirTitle}]]`; return api.postWithToken('csrf', { action: 'edit', title: redirTitle, text: content, summary: summary, createonly: true }).done(() => { mw.notify("Redirect created!", { type: 'success', tag: 'comrade', classes: ['comrade-success'] }); $(`#${elementId}`).fadeOut(); }); } function getSmartSortKey(fullName, entity) { const countryIds = entity.claims?.P27?.map(c => c.mainsnak?.datavalue?.value?.id) || []; const locationIds = entity.claims?.P17?.map(c => c.mainsnak?.datavalue?.value?.id) || []; const placeIds = [...(entity.claims?.P19 || []), ...(entity.claims?.P119 || [])].map(c => c.mainsnak?.datavalue?.value?.id).filter(Boolean); const allRelevantIds = [...countryIds, ...locationIds, ...placeIds]; const birthYear = parseInt(entity.claims?.P569?.[0]?.mainsnak?.datavalue?.value?.time?.match(/[+-](\d{4})/)?.[1]) || 2026; if (fullName.startsWith("Saint ")) return fullName.replace("Saint ", ""); const arabicParticles = /\b(Abu|Abd|Abdel|Abdul|ben|bin|bint)\b/i; if (fullName.match(arabicParticles)) { if (birthYear > 1900) { const parts = fullName.split(' '); const binIndex = parts.findIndex(p => p.toLowerCase() === 'bin' || p.toLowerCase() === 'ben'); if (binIndex > 0) return parts.slice(binIndex).join(' ') + ', ' + parts.slice(0, binIndex).join(' '); } else { return fullName; } } const eastAsianQids = ["Q148", "Q184", "Q884", "Q424", "Q881", "Q17"]; if (allRelevantIds.some(id => eastAsianQids.includes(id))) { if (allRelevantIds.includes("Q17") && birthYear > 1885) return westernSort(fullName); const parts = fullName.split(' '); if (parts.length > 1) return `${parts[0]}, ${parts.slice(1).join(' ')}`; } return westernSort(fullName); } function westernSort(name) { let cleanName = name; if (name.startsWith("O'")) cleanName = name.replace("O'", "O"); const parts = cleanName.split(' '); if (parts.length < 2) return cleanName; const surname = parts.pop(); if (["Jr.", "Jr", "III", "II", "Sr.", "Sr"].includes(surname)) { const actualSurname = parts.pop(); return `${actualSurname}, ${parts.join(' ')} ${surname}`; } return `${surname}, ${parts.join(' ')}`; } async function performDeorphan() { const api = new mw.Api(); await api.edit(mw.config.get('wgPageName'), function(rev) { let text = rev.content; const summary = 'Article has backlinks; removed [[Template:Orphan|{{Orphan}}]]'; text = text.replace(/\{\{Orphan\s*(?:\|[^}]*)?\}\}\s*/gi, ''); text = text.replace(/(\{\{Multiple[ _]issues\s*)\|\s*\|/gi, '$1|'); text = replaceMI(text); text = text.replace(/\n{3,}/g, '\n\n').trim(); return { text, summary, minor: true }; }); mw.notify('Orphan tag removed!', { type: 'success', tag: 'comrade', classes: ['comrade-success'] }); setTimeout(() => location.reload(), 700); } function replaceMI(text) { const miStart = /\{\{Multiple[ _]issues\s*\|/gi; let result = ''; let lastIndex = 0; let match; while ((match = miStart.exec(text)) !== null) { const start = match.index; result += text.slice(lastIndex, start); let depth = 0; let i = start; while (i < text.length) { if (text[i] === '{' && text[i + 1] === '{') { depth++; i += 2; } else if (text[i] === '}' && text[i + 1] === '}') { depth--; i += 2; if (depth === 0) break; } else { i++; } } const end = i; const full = text.slice(start, end); const pipeIdx = full.indexOf('|'); const inner = full.slice(pipeIdx + 1, full.length - 2).trim(); const topLevel = extractTopLevelTemplates(inner); if (topLevel.length === 0) { result += ''; } else if (topLevel.length === 1) { result += topLevel[0].trim(); } else { result += full; } lastIndex = end; miStart.lastIndex = lastIndex; } result += text.slice(lastIndex); return result; } function extractTopLevelTemplates(inner) { const templates = []; let i = 0; while (i < inner.length) { if (inner[i] === '{' && inner[i + 1] === '{') { let depth = 0; const start = i; while (i < inner.length) { if (inner[i] === '{' && inner[i + 1] === '{') { depth++; i += 2; } else if (inner[i] === '}' && inner[i + 1] === '}') { depth--; i += 2; if (depth === 0) break; } else { i++; } } templates.push(inner.slice(start, i)); } else { i++; } } return templates; } async function performSortCorrection(newName, type) { const api = new mw.Api(); const title = mw.config.get("wgPageName"); try { const data = await api.get({ action: 'query', prop: 'revisions', titles: title, rvprop: 'content', formatversion: 2 }); let content = data.query.pages[0].revisions[0].content; const dsRegex = /\{\{(?:DEFAULTSORT|Defaultsort):[^}]+\}\}/i; const newTag = `{{DEFAULTSORT:${newName}}}`; let actionDesc = type === "add" ? "added" : "corrected"; if (dsRegex.test(content)) { content = content.replace(dsRegex, newTag); } else { const catRegex = /\[\[Category:/i; if (catRegex.test(content)) { content = content.replace(catRegex, `${newTag}\n[[Category:`); } else { content += `\n\n${newTag}`; } } await api.postWithToken('csrf', { action: 'edit', title: title, text: content, summary: `Setting DEFAULTSORT to ${newName}`, nocreate: true }); mw.notify(`DEFAULTSORT ${actionDesc} to ${newName}!`, { title: 'Comrade Success', type: 'success' }); setTimeout(() => location.reload(), 700); } catch (err) { mw.notify('Failed to save DEFAULTSORT.', { type: 'error' }); } } function stripDiacritics(str) { return str.normalize("NFD").replace(/[\u0300-\u036f]/g, ""); } function renderSortNudge(target, reason) { const $dsNudge = $('<div>').addClass('comrade-container comrade-nudge'); const $header = $('<div>').addClass('comrade-header'); const $btn = $('<button>').text(`Correct to: ${target}`).click(() => performSortCorrection(target, "format")); $header.append($('<div>').append($('<strong>').text('DEFAULTSORT:'), ` ${reason} `, $btn)); $dsNudge.append($header); appendDismiss($dsNudge); } async function fetchWikidataNameLabels(entity) { const familyIds = entity.claims?.P734?.map(c => c.mainsnak.datavalue.value.id) || []; const givenIds = entity.claims?.P735?.map(c => c.mainsnak.datavalue.value.id) || []; const allNameIds = [...new Set([...familyIds, ...givenIds])]; if (allNameIds.length === 0) return { givens: [], surnames: [] }; const nameData = await $.ajax({ url: "https://www.wikidata.org/w/api.php", data: { action: 'wbgetentities', ids: allNameIds.join('|'), props: 'labels', languages: 'en', format: 'json', origin: '*' }, dataType: 'json' }); return { givens: givenIds.map(id => nameData.entities[id]?.labels?.en?.value).filter(Boolean), surnames: familyIds.map(id => nameData.entities[id]?.labels?.en?.value).filter(Boolean) }; } function fixNameCasing(part, referenceName) { return part.split(' ').map(word => { const match = referenceName.match(new RegExp(`\\b${word}\\b`, 'i')); if (match) return match[0]; return referenceName.split(' ').find(tWord => word.toLowerCase().startsWith(tWord.toLowerCase()) || tWord.toLowerCase().startsWith(word.toLowerCase())) || word; }).join(' '); } function getLongNameFromWikitext(wikitext) { const firstLine = wikitext.split('\n').find(l => l.includes("'''")); if (!firstLine) return null; const boldMatch = firstLine.match(/'''(.+?)'''/); if (!boldMatch) return null; return boldMatch[1].replace(/\s*([“"«《„‹「『'].+?[”"»》”›」』']|\([^)\n]*\))\s*/g, ' ').replace(/\s+/g, ' ').trim(); } if (mw.config.get("wgDBname") === "enwiki" && mw.config.get("wgUserId") === 19244234 && mw.config.get("wgNamespaceNumber") === 0 && mw.config.get("wgAction") === "view") { $(document).ready(async function() { const api = new mw.Api(); const qid = mw.config.get("wgWikibaseItemId"); try { const [pageData, backlinkData] = await Promise.all([ api.get({ action: 'query', prop: 'revisions', titles: mw.config.get("wgPageName"), rvprop: 'content', formatversion: 2 }), api.get({ action: 'query', list: 'backlinks', blfilterredir: 'nonredirects', bllimit: 50, blnamespace: 0, bltitle: mw.config.get("wgPageName"), formatversion: 2 }) ]); const page = pageData.query.pages[0]; if (!page || page.missing || !page.revisions) return; const wikitext = page.revisions[0].content; const currentTitle = mw.config.get("wgTitle"); const cleanTitle = stripDiacritics(currentTitle); const isOrphanTagged = /\{\{\s*(Orphan|Do-attempt|Lonely|Orp|Orphaned article)/i.test(wikitext) || /\| *orphan *=/i.test(wikitext); const backLinkCount = backlinkData.query.backlinks.length; if (isOrphanTagged && backLinkCount >= 1) { const $container = $('<div>').addClass('comrade-container comrade-status'); const $header = $('<div>').addClass('comrade-header'); const $btn = $('<button>').text('Remove orphan tag').click(() => performDeorphan()); $header.append($('<div>').append($('<strong>').text('Status:'), ` Article has ${backLinkCount} backlink(s).`, $btn)); $container.append($header); appendDismiss($container); } if (cleanTitle !== currentTitle) checkAndRenderRedirect(cleanTitle, currentTitle, "R to diacritic", "Diacritic"); checkDomainRedirect(qid, currentTitle); if (qid) { const wikiData = await $.ajax({ url: "https://www.wikidata.org/w/api.php", data: { action: 'wbgetentities', ids: qid, props: 'claims|labels', languages: 'en', format: 'json', origin: '*' }, dataType: 'json' }); const entity = wikiData.entities[qid]; const isHuman = entity?.claims?.P31?.some(c => c.mainsnak?.datavalue?.value?.id === "Q5"); const tClean = currentTitle.replace(/\s*\(.*?\)\s*/g, '').trim(); const nameParts = tClean.split(' '); const hasFamilyNameHatnote = /\{\{family[ _]name[ _]hatnote/i.test(wikitext); const hasShortDesc = /\{\{\s*[Ss]hort description/i.test(wikitext); const dsMatch = wikitext.match(/\{\{(?:DEFAULTSORT|Defaultsort):([^}]+)\}\}/i); const isOrphan = isOrphanTagged && backLinkCount < 1; const primarySurname = hasFamilyNameHatnote ? nameParts[0] : (getSmartSortKey(tClean, entity).split(',')[0] || nameParts[nameParts.length - 1]); let targetSortName = ""; if (isHuman) { const { givens, surnames } = await fetchWikidataNameLabels(entity); const refName = entity.labels?.en?.value || currentTitle; if (dsMatch) { const currentDS = dsMatch[1].trim(); targetSortName = currentDS; if (currentDS.includes(',')) { let [lastPart, firstPart] = currentDS.split(',').map(s => s.trim()); if (firstPart.toLowerCase().endsWith(lastPart.toLowerCase())) { firstPart = firstPart.substring(0, firstPart.length - lastPart.length).trim(); targetSortName = `${fixNameCasing(lastPart, refName)}, ${fixNameCasing(firstPart, refName)}`; renderSortNudge(targetSortName, "Redundant surname in given name field."); } else if (givens.length > 0 && lastPart.split(' ').length > 1) { const misplacedGiven = lastPart.split(' ').find(part => givens.some(gn => gn.toLowerCase() === part.toLowerCase())); if (misplacedGiven) { const newSurname = lastPart.split(' ').filter(p => p !== misplacedGiven).join(' '); targetSortName = `${fixNameCasing(newSurname, refName)}, ${fixNameCasing(misplacedGiven + ' ' + firstPart, refName)}`; renderSortNudge(targetSortName, `Wikidata suggests "${misplacedGiven}" is a given name.`); } } } } else { targetSortName = hasFamilyNameHatnote ? `${nameParts[0]}, ${nameParts.slice(1).join(' ')}` : getSmartSortKey(tClean, entity); const $dsMissing = $('<div>').addClass('comrade-container comrade-nudge'); const $header = $('<div>').addClass('comrade-header'); const $btn = $('<button>').text(`Add: {{DEFAULTSORT:${targetSortName}}}`).click(() => performSortCorrection(targetSortName, "add")); $header.append($('<div>').append($('<strong>').text('DEFAULTSORT:'), ` Tag is missing. `, $btn)); $dsMissing.append($header); appendDismiss($dsMissing); } const longName = getLongNameFromWikitext(wikitext); if (longName && longName.length > tClean.length) { let sortKey = hasFamilyNameHatnote ? `${longName.split(' ')[0]}, ${longName.split(' ').slice(1).join(' ')}` : getSmartSortKey(longName, entity); const rLongWikitext = `#REDIRECT [[${currentTitle}]]\n\n{{Redirect category shell|\n{{R from long name}}\n}}\n{{DEFAULTSORT:${sortKey}}}`; checkAndRenderRedirect(longName, currentTitle, null, "Long name", rLongWikitext); } if (targetSortName) { let targetPage = currentTitle.includes(' (') ? currentTitle.split(' (')[0] : currentTitle; let rCat = targetPage !== currentTitle ? "R from ambiguous sort name" : "R from sort name"; if (targetSortName.includes(',')) { const p = targetSortName.split(','); rCat += `|${p[0].trim().charAt(0).toUpperCase()}|${p[1].trim().charAt(0).toUpperCase()}`; } checkAndRenderRedirect(targetSortName, targetPage, rCat, "Sort name"); } const finalFamilyNames = new Set(); const finalGivenNames = new Set(); surnames.forEach(fn => { if (tClean.toLowerCase().includes(fn.toLowerCase())) { fn.split(' ').forEach(part => finalFamilyNames.add(part)); finalFamilyNames.add(fn); } }); givens.forEach(gn => { if (tClean.toLowerCase().includes(gn.toLowerCase())) finalGivenNames.add(gn); }); if (finalFamilyNames.size === 0 && nameParts.length >= 2) finalFamilyNames.add(nameParts[nameParts.length - 1]); if (finalGivenNames.size === 0 && nameParts.length >= 2) finalGivenNames.add(nameParts[0]); const getPriorityTarget = async (name, type) => { const titles = type === 'surname' ? [`List of people with surname ${name}`, `List of people with the English surname ${name}`, `${name} (surname)`] : [`List of people with given name ${name}`, `${name} (given name)`]; const res = await api.get({ action: 'query', titles: titles.join('|'), formatversion: 2 }); return titles.find(t => res.query.pages.find(pg => pg.title === t && !pg.missing)); }; for (const name of finalGivenNames) { if (name.toLowerCase() === primarySurname.toLowerCase()) continue; const target = await getPriorityTarget(name, 'given'); if (target) await checkNameList(name, 'given name', currentTitle, hasShortDesc, isOrphan, target); } for (const name of finalFamilyNames) { const target = await getPriorityTarget(name, 'surname'); if (target) await checkNameList(name, 'surname', currentTitle, hasShortDesc, isOrphan, target); } } } } catch (err) { console.error("Comrade error:", err); } }); } })(); (function() { if (window.IllWill) return; const STRIKEOUT = true; const HIDE = 'hide'; const IllWill = { Version: "1.1.1", Attribution: 'created by <a target="_blank" href="/wiki/User:Cobaltcigs">cobaltcigs</a>', Summary: "Added interlanguage links using IllWill.js", DataApi: "https://www.wikidata.org/w/api.php", LocalLang: mw.config.get("wgPageContentLanguage"), Disambiguator: / \(.*\)$/, SiteLinks: {}, Config: { MaxLanguages: 5, IgnoreScientific: STRIKEOUT, AutoDiff: true }, css: ` #illwill { clear: both; margin-bottom: 1.5em; border: 1px solid #a2a9b1; padding: 15px; background: #f8f9fa; box-shadow: 0 2px 4px rgba(0,0,0,0.1); } .ill-sitelinks a { display: inline-block; margin-bottom: 3px; font-size: 0.9em; color: #36c; } .ill-size-tag { font-size: 0.8em; color: #72777d; margin-left: 6px; white-space: nowrap; } .illwill-ignore { text-decoration: line-through; color: #72777d; font-size: 0.85em; } .ill-x { width: 35px; text-align: center; } .ill-input, .ill-output { font-family: 'Courier New', monospace; white-space: pre-wrap; font-size: 0.9em; background: #fff; border: 1px solid #eaecf0; padding: 4px; border-radius: 2px; } #ill-buttons { text-align: right; padding: 10px; border-top: 1px solid #a2a9b1; margin-top: 10px; } #ill-buttons button { margin-left: 10px; cursor: pointer; padding: 6px 16px; border-radius: 2px; border: 1px solid #a2a9b1; transition: all 0.2s; } #ill-ok { background: #36c; color: #fff; border-color: #36c !important; font-weight: bold; } #ill-ok:hover { background: #447ff5; } #ill-ok:disabled { background: #eaecf0; color: #72777d; border-color: #c8ccd1 !important; cursor: not-allowed; opacity: 0.7; } #ill-table { width: 100%; border-collapse: collapse; margin-top: 10px; background: white; } #ill-table th { background: #f2f2f2; text-align: left; padding: 8px; border: 1px solid #a2a9b1; } #ill-table td { padding: 8px; border: 1px solid #a2a9b1; vertical-align: top; } #ill-table caption { background: #eaffea; font-weight: bold; padding: 10px; border: 1px solid #a2a9b1; border-bottom: none; font-size: 1.1em; } #ill-help { font-size: 0.85em; color: #54595d; padding: 10px; line-height: 1.4; } .ill-loading-inline { font-style: italic; color: #72777d; font-size: 0.9em; display: block; margin: 5px 0; } `, setup() { if (!["edit", "submit"].includes(mw.config.get('wgAction'))) return; mw.loader.addStyleTag(this.css); const link = mw.util.addPortletLink('p-cactions', '#', 'IllWill', 'ca-illwill', "Add interlanguage links via Wikidata"); if (link) { link.addEventListener('click', (e) => { e.preventDefault(); this.makePanel(); }); } }, norm(s) { if (!s) return ""; const t = s.trim().replace(/[\s_]+/g, " "); return t.charAt(0).toUpperCase() + t.slice(1); }, async getRedLinks($textbox) { const txt = $textbox.textSelection('getContents') || ""; const wl = txt.match(/\[\[[^[\]\n]+\]\]/g); if (!wl) return { reds: [], txt }; const api = new mw.Api(); const textToParse = wl.join("").replace(/\|[^\]]+/g, ""); try { const data = await api.post({ action: 'parse', text: textToParse, contentmodel: 'wikitext', formatversion: 2 }); const tempDiv = document.createElement('div'); tempDiv.innerHTML = data.parse.text; const reds = Array.from(tempDiv.querySelectorAll("a.new")).map(x => { const urlParams = new URLSearchParams(x.href.split('?')[1]); return urlParams.get('title')?.replace(/_/g, " "); }).filter(Boolean); return { reds: [...new Set(reds)], txt }; } catch (e) { return { reds: [], txt }; } }, async makePanel() { const $editform = $('#editform'); const $textbox = $('#wpTextbox1'); $('#illwill').remove(); $editform.hide(); const $wrapper = $('<div id="illwill">Loading redlinks...</div>').insertBefore($editform); const { reds, txt } = await this.getRedLinks($textbox); const wtLinks = []; reds.forEach(title => { const escaped = title.replace(/[.*+?^${}()|[\]\\]/g, '\\$&').replace(/\s/g, "[\\s_]+"); const re = new RegExp("\\[\\[\\s*" + escaped + "\\s*(?:\\|[^\\[\\]]+)?\\]\\]", "ig"); const match = txt.match(re); if (match && !wtLinks.some(z => z.title === title)) { wtLinks.push({ link: match[0], title }); } }); if (!wtLinks.length) { const $back = $('<button>Quit</button>').on('click', () => { $wrapper.remove(); $editform.show(); }); $wrapper.empty().append($('<strong>No valid redlinks found in text.</strong> '), $back); return; } const $table = $(` <table id="ill-table" class="wikitable"> <caption>IllWill.js (v${this.Version})</caption> <thead> <tr> <th class="ill-x"><input type="checkbox" id="ill-select-all" disabled></th> <th>Input link</th> <th>Possible Wikidata matches</th> <th>Sitelinks (top ${this.Config.MaxLanguages} by size)</th> <th>Resulting wikitext</th> </tr> </thead> <tbody></tbody> <tfoot> <tr> <td colspan="3" id="ill-help">Carefully examine possible Wikidata matches.</td> <td colspan="2" id="ill-buttons"> <button id="ill-cancel">Cancel</button> <button id="ill-ok" disabled>Show changes</button> </td> </tr> </tfoot> </table> `); const $tbody = $table.find('tbody'); wtLinks.forEach((item, i) => { $tbody.append(` <tr id="ill-row-${i}" data-index="${i}"> <td class="ill-x"><input type="checkbox" class="ill-row-check" disabled></td> <td class="ill-input">${this.escapeHTML(item.link)}</td> <td class="ill-wd-item"><span class="ill-loading-inline">Searching...</span></td> <td class="ill-sitelinks"></td> <td class="ill-output"></td> </tr> `); }); $wrapper.empty().append($table); const chunkSize = 5; for (let i = 0; i < wtLinks.length; i += chunkSize) { const chunk = wtLinks.slice(i, i + chunkSize); await Promise.all(chunk.map((item, idx) => this.fetchWikidataOptimized(item.title, i + idx))); } $table.on('click', '#ill-cancel', () => { $editform.show(); $wrapper.remove(); }); $table.on('click', '#ill-ok', () => this.onOkButton($editform, $wrapper, $textbox)); $table.on('change', '#ill-select-all', (e) => { const isChecked = $(e.target).is(':checked'); $table.find('.ill-row-check:not(:disabled)').each(function() { $(this).prop('checked', isChecked).trigger('change'); }); }); $table.on('change', '.ill-row-check', (e) => { this.onCheckbox(e); this.updateOkButtonState($table); }); $table.on('change', 'input[type="radio"]', (e) => { this.showSiteLinks(e); }); }, async fetchWikidataOptimized(title, index) { const query = title.replace(this.Disambiguator, ""); const url = `${this.DataApi}?action=wbsearchentities&search=${encodeURIComponent(query)}&language=${this.LocalLang}&limit=5&format=json&origin=*`; try { const resp = await fetch(url); const data = await resp.json(); const results = data.search; const $cell = $(`#ill-row-${index} .ill-wd-item`); if (!results || !results.length) { $cell.html('<span class="ill-na">(no results)</span>'); return; } const entityIds = results.map(r => r.id); await this.fetchEntities(entityIds, index, $cell); } catch (e) { $(`#ill-row-${index} .ill-wd-item`).text("Search failed."); } }, async fetchEntities(ids, rowIndex, $cell) { const url = `${this.DataApi}?action=wbgetentities&ids=${ids.join('|')}&props=labels|descriptions|claims|sitelinks&format=json&origin=*`; try { const resp = await fetch(url); const data = await resp.json(); $cell.empty(); ids.forEach(qNum => { const entity = data.entities[qNum]; if (!entity) return; const isScientific = entity.claims?.P31?.some(s => s.mainsnak?.datavalue?.value?.id === "Q13442814"); if (isScientific && this.Config.IgnoreScientific === HIDE) return; const desc = entity.descriptions?.[this.LocalLang]?.value || entity.descriptions?.en?.value || ""; const label = entity.labels?.[this.LocalLang]?.value || entity.labels?.en?.value || qNum; const isStrikeout = isScientific && this.Config.IgnoreScientific === STRIKEOUT; const $div = $(` <div class="${isStrikeout ? 'illwill-ignore' : ''}"> <input type="radio" name="selection-${rowIndex}" value="${qNum}" id="radio-${qNum}" ${isStrikeout ? 'disabled' : ''}> <label for="radio-${qNum}"> <a href="https://wikidata.org/wiki/${qNum}" target="_blank">${this.escapeHTML(label)}</a>: <span class="ill-desc">${desc ? this.escapeHTML(desc) : '<i>no description</i>'}</span> </label> </div> `); $cell.append($div); this.SiteLinks[qNum] = entity.sitelinks || {}; }); } catch (e) { $cell.text("Detail fetch failed."); } }, updateOkButtonState($table) { const $rows = $table.find('.ill-row-check:not(:disabled)'); const $checkedRows = $rows.filter(':checked'); const anyEnabled = $rows.length > 0; $table.find('#ill-ok').prop('disabled', $checkedRows.length === 0); const $master = $table.find('#ill-select-all'); $master.prop('disabled', !anyEnabled); if (anyEnabled && $rows.length === $checkedRows.length) { $master.prop('checked', true); } else { $master.prop('checked', false); } }, async showSiteLinks(e) { const isManualToggling = e.fromCheckbox || false; const qNum = e.target.value; const $row = $(e.target).closest('tr'); const sitelinks = this.SiteLinks[qNum]; const $checkbox = $row.find('.ill-row-check'); const $sitelinkCell = $row.find('.ill-sitelinks'); const $outputCell = $row.find('.ill-output'); const $table = $('#ill-table'); const effectiveMax = Math.min(Math.max(this.Config.MaxLanguages, 3), 6); const validKeys = Object.keys(sitelinks).filter(k => k.endsWith('wiki') && !k.includes('commons')); $sitelinkCell.html('<span class="ill-loading-inline">Measuring articles...</span>'); $outputCell.empty(); if (!isManualToggling) { $checkbox.prop('disabled', true).prop('checked', false); } const candidates = validKeys.slice(0, 25); const sizeMap = []; await Promise.all(candidates.map(async (key) => { const lang = key.replace('wiki', '').replace(/_/g, '-'); const title = sitelinks[key].title; const endpoint = `https://${lang}.wikipedia.org/w/api.php?action=query&titles=${encodeURIComponent(title)}&prop=info&format=json&origin=*`; try { const res = await fetch(endpoint).then(r => r.json()); const page = Object.values(res.query.pages)[0]; sizeMap.push({ lang, title, length: page.length || 0 }); } catch (err) { sizeMap.push({ lang, title, length: 0 }); } })); sizeMap.sort((a, b) => b.length - a.length); const topLinks = sizeMap.slice(0, effectiveMax); $sitelinkCell.html(topLinks.map(item => { const kbValue = Math.round(item.length / 1024); return `<div><a href="https://${item.lang}.wikipedia.org/wiki/${encodeURIComponent(item.title)}" target="_blank">${item.lang}:${this.escapeHTML(item.title)}</a> <span class="ill-size-tag">(${kbValue} kB)</span></div>`; }).join("")); const inputWikitext = $row.find('.ill-input').text(); const match = inputWikitext.match(/\[\[(.*?)\]\]/); if (match) { const parts = match[1].split('|'); const targetPage = parts[0].trim(); const surfaceName = (parts[1] || parts[0]).trim(); const illLangs = topLinks.map(item => { const isSameTitle = this.norm(item.title) === this.norm(targetPage); return `|${item.lang}|${isSameTitle ? '' : item.title}`; }).join(""); const ltParam = (this.norm(surfaceName) === this.norm(targetPage)) ? "" : `|lt=${surfaceName}`; $outputCell.text(`{{ill|${targetPage}${ltParam}${illLangs}}}`); } $checkbox.prop('disabled', !topLinks.length); if (!isManualToggling) { $checkbox.prop('checked', !!topLinks.length); } this.updateOkButtonState($table); }, onCheckbox(e) { const $row = $(e.target).closest('tr'); const $radio = $row.find('input[type="radio"]:checked'); const isChecked = $(e.target).is(':checked'); if (isChecked) { if ($radio.length) { this.showSiteLinks({ target: $radio[0], fromCheckbox: true }); } } else { $row.find('.ill-sitelinks, .ill-output').empty(); } }, onOkButton($editform, $wrapper, $textbox) { let text = $textbox.textSelection('getContents'); let changed = false; $wrapper.find('.ill-row-check:checked').each(function() { const $row = $(this).closest('tr'); const input = $row.find('.ill-input').text(); const output = $row.find('.ill-output').text(); if (output) { const escapedInput = input.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); text = text.replace(new RegExp(escapedInput, "gi"), output); changed = true; } }); if (changed) { $('#wpSummary').val((i, v) => (v ? v + "; " : "") + this.Summary); $textbox.textSelection('setContents', text); $wrapper.remove(); $editform.show(); if (this.Config.AutoDiff) $('#wpDiff').click(); } }, escapeHTML(str) { return str.replace(/[&<>"']/g, m => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' })[m]); } }; window.IllWill = IllWill; mw.loader.using(['mediawiki.util', 'mediawiki.api', 'jquery.textSelection'], () => { $(() => IllWill.setup()); }); })(); //</nowiki> cl9kmdwzqw1qplqt1sk20x76v6oz5xo 739072 739071 2026-04-22T08:31:45Z Sam Sailor 26820 Test 739072 javascript text/javascript //<nowiki> (function() { var Comrade = Comrade || {}; mw.util.addCSS(` .ambox-Orphan { display: block !important; } .comrade-container { box-shadow: 0 1px 3px rgba(0,0,0,0.1); border-radius: 2px; padding: 10px 15px; margin: 10px 0; display: flex; flex-direction: column; align-items: flex-start; gap: 8px; border: 1px solid #a2a9b1; background: #fcfcfc; line-height: 1.5; } .comrade-header { display: flex; align-items: center; justify-content: space-between; width: 100%; } .comrade-content { display: flex; flex-direction: column; gap: 5px; width: 100%; } .comrade-success { background-color: #d5f5e3 !important; border-left: 5px solid #27ae60 !important; color: #1b5e20 !important; } .comrade-nudge { background: #fff9ea; border-left: 5px solid #f0ad4e; } .comrade-info { background: #eaf3ff; border-left: 5px solid #36c; } .comrade-status { background: #eaf3ff; border-left: 5px solid #36c; } .comrade-container button:not(.comrade-dismiss) { background: #f8f9fa; border: 1px solid #a2a9b1; border-radius: 2px; padding: 2px 10px; cursor: pointer; font-weight: bold; font-size: 0.95em; margin-left: 10px; } .comrade-container button:not(.comrade-dismiss):hover { border-color: #36c; color: #36c; background: #fff; } .comrade-dismiss { background: transparent; border: none; color: #d33; font-weight: bold; cursor: pointer; font-size: 0.9em; } .comrade-dismiss:hover { text-decoration: underline; } .comrade-code-block { background: #f1f1f1; padding: 4px 8px; border-radius: 3px; font-family: monospace; display: inline-block; margin-top: 4px; } `); function appendDismiss($el) { $('<button>').addClass('comrade-dismiss').text('Dismiss').click(function() { $(this).closest('.comrade-container').fadeOut(); }).appendTo($el.find('.comrade-header')); $("#siteSub").after($el); } async function checkAndRenderRedirect(redirTitle, targetTitle, rCategory, labelText, customWikitext) { const api = new mw.Api(); const res = await api.get({ action: 'query', titles: redirTitle, formatversion: 2 }); if (res.query.pages[0].missing) { const safeId = "comrade-redir-" + btoa(unescape(encodeURIComponent(redirTitle))).replace(/=/g, ""); const $container = $('<div>').addClass('comrade-container comrade-info').attr('id', safeId); const $header = $('<div>').addClass('comrade-header'); const summary = `Created redirect from ${labelText.toLowerCase()} to [[${targetTitle}]]`; const $btn = $('<button>').text('Create redirect').click(() => createModernRedirect(redirTitle, targetTitle, rCategory, summary, safeId, customWikitext)); $header.append($('<div>').append($('<strong>').text(`${labelText}: `), `Create redirect from `, $('<code>').text(redirTitle), $btn)); $container.append($header); appendDismiss($container); } } async function checkDomainRedirect(qid, currentTitle) { let domainCandidate = ""; if (qid) { try { const res = await $.ajax({ url: "https://www.wikidata.org/w/api.php", data: { action: 'wbgetclaims', entity: qid, property: 'P856', format: 'json', origin: '*' } }); if (res.claims?.P856) { domainCandidate = res.claims.P856[0].mainsnak.datavalue.value; } } catch (e) { console.log("Comrade: Wikidata API call failed."); } } if (!domainCandidate) { domainCandidate = $(".infobox .url a").last().attr("href") || $(".official-website a").first().attr("href"); } if (domainCandidate) { try { const url = new URL(domainCandidate); let domain = url.hostname.replace(/^www\d*\./, ""); if (domain.includes(".") && url.pathname === "/") { const citationURL = '/api/rest_v1/data/citation/mediawiki/' + encodeURIComponent(domainCandidate); $.ajax({ url: citationURL, method: 'GET', success: function() { checkAndRenderRedirect(domain, currentTitle, "R from domain name", "Domain"); } }); } } catch (e) { console.log("Comrade: Error parsing URL object."); } } } async function checkNameList(name, type, currentTitle, hasShortDesc, isOrphan) { const api = new mw.Api(); const candidates = [`${name} (${type})`, `${name} (${type.toLowerCase()})`, `${name} (name)`, name]; const checked = new Set(); for (const title of candidates) { if (checked.has(title)) continue; checked.add(title); const res = await api.get({ action: 'query', prop: 'revisions', titles: title, rvprop: 'content', formatversion: 2, redirects: 0 }); const page = res.query.pages[0]; if (page && !page.missing) { const text = page.revisions[0].content; const resolvedTitle = page.title; const isNameMatch = /\{\{(Surname|Hndis|Given[ _]name|Forename|Givenname)/i.test(text); const isNameDab = /\{\{(Disambiguation|Dab|Disambig)(?:[^}]*\|(surname|surnames|given[ _]name|given[ _]names)|(?:\s*\}\}))/i.test(text); if (isNameMatch || isNameDab) { const escapedTitle = currentTitle.replace(/[.*+?^${}()|[\]\\]/g, '\\$&').replace(/ /g, '[ _]'); const alreadyListed = new RegExp('(\\[\\[|\\{\\{anbl\\|[ _]*|\\|)' + escapedTitle, 'i').test(text); if (alreadyListed) break; const $container = $('<div>').addClass('comrade-container'); const $header = $('<div>').addClass('comrade-header'); const $content = $('<div>').addClass('comrade-content'); if (isOrphan) { $container.addClass('comrade-nudge'); $header.append($('<strong>').text('Comrade nudge:')); } else { $container.addClass('comrade-info'); $header.append($('<strong>').text('Informative:')); } $content.append($('<span>').append(`${type.charAt(0).toUpperCase() + type.slice(1)} not listed at `, $('<a>').attr({ href: mw.util.getUrl(resolvedTitle), target: '_blank' }).text(resolvedTitle), "; should it be?")); const snippet = '* {{anbl|' + currentTitle + '}}'; const $snippetWrapper = $('<div>').css({ 'display': 'flex', 'align-items': 'center', 'gap': '10px', 'margin-top': '4px' }); const $instructionSpan = $('<span>').append('If the Short description is good, consider adding ', $('<code>').text(snippet).css({ 'background-color': '#f8f9fa', 'border': '1px solid #eaecf0', 'border-radius': '2px', 'padding': '1px 4px' })); const $copyBtn = $('<button>').text('Copy').css('margin-left', '0').click(function() { navigator.clipboard.writeText(snippet).then(() => { const $this = $(this); const originalText = $this.text(); $this.text('Copied!').prop('disabled', true); setTimeout(() => { $this.text(originalText).prop('disabled', false); }, 1500); }); }); $snippetWrapper.append($instructionSpan, $copyBtn); $content.append($snippetWrapper); if (!hasShortDesc) { $content.append($('<span>').css({ 'color': '#d33', 'font-weight': 'bold', 'margin-top': '5px' }).text('⚠️ Missing short description: Please add a concise one before listing.')); } $container.append($header, $content); appendDismiss($container); break; } } } } async function createModernRedirect(redirTitle, targetTitle, rCategory, customSummary, elementId, customWikitext) { const api = new mw.Api(); const content = customWikitext || `#REDIRECT [[${targetTitle}]]\n\n{{Redirect category shell|\n{{${rCategory}}}\n}}`; const summary = customSummary || `Created redirect from [[${redirTitle}]]`; return api.postWithToken('csrf', { action: 'edit', title: redirTitle, text: content, summary: summary, createonly: true }).done(() => { mw.notify("Redirect created!", { type: 'success', tag: 'comrade', classes: ['comrade-success'] }); $(`#${elementId}`).fadeOut(); }); } function getSmartSortKey(fullName, entity) { const countryIds = entity.claims?.P27?.map(c => c.mainsnak?.datavalue?.value?.id) || []; const locationIds = entity.claims?.P17?.map(c => c.mainsnak?.datavalue?.value?.id) || []; const placeIds = [...(entity.claims?.P19 || []), ...(entity.claims?.P119 || [])].map(c => c.mainsnak?.datavalue?.value?.id).filter(Boolean); const allRelevantIds = [...countryIds, ...locationIds, ...placeIds]; const birthYear = parseInt(entity.claims?.P569?.[0]?.mainsnak?.datavalue?.value?.time?.match(/[+-](\d{4})/)?.[1]) || 2026; if (fullName.startsWith("Saint ")) return fullName.replace("Saint ", ""); const arabicParticles = /\b(Abu|Abd|Abdel|Abdul|ben|bin|bint)\b/i; if (fullName.match(arabicParticles)) { if (birthYear > 1900) { const parts = fullName.split(' '); const binIndex = parts.findIndex(p => p.toLowerCase() === 'bin' || p.toLowerCase() === 'ben'); if (binIndex > 0) return parts.slice(binIndex).join(' ') + ', ' + parts.slice(0, binIndex).join(' '); } else { return fullName; } } const eastAsianQids = ["Q148", "Q184", "Q884", "Q424", "Q881", "Q17"]; if (allRelevantIds.some(id => eastAsianQids.includes(id))) { if (allRelevantIds.includes("Q17") && birthYear > 1885) return westernSort(fullName); const parts = fullName.split(' '); if (parts.length > 1) return `${parts[0]}, ${parts.slice(1).join(' ')}`; } return westernSort(fullName); } function westernSort(name) { let cleanName = name; if (name.startsWith("O'")) cleanName = name.replace("O'", "O"); const parts = cleanName.split(' '); if (parts.length < 2) return cleanName; const surname = parts.pop(); if (["Jr.", "Jr", "III", "II", "Sr.", "Sr"].includes(surname)) { const actualSurname = parts.pop(); return `${actualSurname}, ${parts.join(' ')} ${surname}`; } return `${surname}, ${parts.join(' ')}`; } async function performDeorphan() { const api = new mw.Api(); await api.edit(mw.config.get('wgPageName'), function(rev) { let text = rev.content; const summary = 'Article has backlinks; removed [[Template:Orphan|{{Orphan}}]]'; text = text.replace(/\{\{Orphan\s*(?:\|[^}]*)?\}\}\s*/gi, ''); text = text.replace(/(\{\{Multiple[ _]issues\s*)\|\s*\|/gi, '$1|'); text = replaceMI(text); text = text.replace(/\n{3,}/g, '\n\n').trim(); return { text, summary, minor: true }; }); mw.notify('Orphan tag removed!', { type: 'success', tag: 'comrade', classes: ['comrade-success'] }); setTimeout(() => location.reload(), 700); } function replaceMI(text) { const miStart = /\{\{Multiple[ _]issues\s*\|/gi; let result = ''; let lastIndex = 0; let match; while ((match = miStart.exec(text)) !== null) { const start = match.index; result += text.slice(lastIndex, start); let depth = 0; let i = start; while (i < text.length) { if (text[i] === '{' && text[i + 1] === '{') { depth++; i += 2; } else if (text[i] === '}' && text[i + 1] === '}') { depth--; i += 2; if (depth === 0) break; } else { i++; } } const end = i; const full = text.slice(start, end); const pipeIdx = full.indexOf('|'); const inner = full.slice(pipeIdx + 1, full.length - 2).trim(); const topLevel = extractTopLevelTemplates(inner); if (topLevel.length === 0) { result += ''; } else if (topLevel.length === 1) { result += topLevel[0].trim(); } else { result += full; } lastIndex = end; miStart.lastIndex = lastIndex; } result += text.slice(lastIndex); return result; } function extractTopLevelTemplates(inner) { const templates = []; let i = 0; while (i < inner.length) { if (inner[i] === '{' && inner[i + 1] === '{') { let depth = 0; const start = i; while (i < inner.length) { if (inner[i] === '{' && inner[i + 1] === '{') { depth++; i += 2; } else if (inner[i] === '}' && inner[i + 1] === '}') { depth--; i += 2; if (depth === 0) break; } else { i++; } } templates.push(inner.slice(start, i)); } else { i++; } } return templates; } async function performSortCorrection(newName, type) { const api = new mw.Api(); const title = mw.config.get("wgPageName"); try { const data = await api.get({ action: 'query', prop: 'revisions', titles: title, rvprop: 'content', formatversion: 2 }); let content = data.query.pages[0].revisions[0].content; const dsRegex = /\{\{(?:DEFAULTSORT|Defaultsort):[^}]+\}\}/i; const newTag = `{{DEFAULTSORT:${newName}}}`; let actionDesc = type === "add" ? "added" : "corrected"; if (dsRegex.test(content)) { content = content.replace(dsRegex, newTag); } else { const catRegex = /\[\[Category:/i; if (catRegex.test(content)) { content = content.replace(catRegex, `${newTag}\n[[Category:`); } else { content += `\n\n${newTag}`; } } await api.postWithToken('csrf', { action: 'edit', title: title, text: content, summary: `Setting DEFAULTSORT to ${newName}`, nocreate: true }); mw.notify(`DEFAULTSORT ${actionDesc} to ${newName}!`, { title: 'Comrade Success', type: 'success' }); setTimeout(() => location.reload(), 700); } catch (err) { mw.notify('Failed to save DEFAULTSORT.', { type: 'error' }); } } function stripDiacritics(str) { return str.normalize("NFD").replace(/[\u0300-\u036f]/g, ""); } function renderSortNudge(target, reason) { const $dsNudge = $('<div>').addClass('comrade-container comrade-nudge'); const $header = $('<div>').addClass('comrade-header'); const $btn = $('<button>').text(`Correct to: ${target}`).click(() => performSortCorrection(target, "format")); $header.append($('<div>').append($('<strong>').text('DEFAULTSORT:'), ` ${reason} `, $btn)); $dsNudge.append($header); appendDismiss($dsNudge); } async function fetchWikidataNameLabels(entity) { const familyIds = entity.claims?.P734?.map(c => c.mainsnak.datavalue.value.id) || []; const givenIds = entity.claims?.P735?.map(c => c.mainsnak.datavalue.value.id) || []; const allNameIds = [...new Set([...familyIds, ...givenIds])]; if (allNameIds.length === 0) return { givens: [], surnames: [] }; const nameData = await $.ajax({ url: "https://www.wikidata.org/w/api.php", data: { action: 'wbgetentities', ids: allNameIds.join('|'), props: 'labels', languages: 'en', format: 'json', origin: '*' }, dataType: 'json' }); return { givens: givenIds.map(id => nameData.entities[id]?.labels?.en?.value).filter(Boolean), surnames: familyIds.map(id => nameData.entities[id]?.labels?.en?.value).filter(Boolean) }; } function fixNameCasing(part, referenceName) { return part.split(' ').map(word => { const match = referenceName.match(new RegExp(`\\b${word}\\b`, 'i')); if (match) return match[0]; return referenceName.split(' ').find(tWord => word.toLowerCase().startsWith(tWord.toLowerCase()) || tWord.toLowerCase().startsWith(word.toLowerCase())) || word; }).join(' '); } function getLongNameFromWikitext(wikitext) { const firstLine = wikitext.split('\n').find(l => l.includes("'''")); if (!firstLine) return null; const boldMatch = firstLine.match(/'''(.+?)'''/); if (!boldMatch) return null; return boldMatch[1].replace(/\s*([“"«《„‹「『'].+?[”"»》”›」』']|\([^)\n]*\))\s*/g, ' ').replace(/\s+/g, ' ').trim(); } if (mw.config.get("wgDBname") === "enwiki" && mw.config.get("wgUserId") === 19244234 && mw.config.get("wgNamespaceNumber") === 0 && mw.config.get("wgAction") === "view") { $(document).ready(async function() { const api = new mw.Api(); const qid = mw.config.get("wgWikibaseItemId"); try { const [pageData, backlinkData] = await Promise.all([ api.get({ action: 'query', prop: 'revisions', titles: mw.config.get("wgPageName"), rvprop: 'content', formatversion: 2 }), api.get({ action: 'query', list: 'backlinks', blfilterredir: 'nonredirects', bllimit: 50, blnamespace: 0, bltitle: mw.config.get("wgPageName"), formatversion: 2 }) ]); const page = pageData.query.pages[0]; if (!page || page.missing || !page.revisions) return; const wikitext = page.revisions[0].content; const currentTitle = mw.config.get("wgTitle"); const cleanTitle = stripDiacritics(currentTitle); const isOrphanTagged = /\{\{\s*(Orphan|Do-attempt|Lonely|Orp|Orphaned article)/i.test(wikitext) || /\| *orphan *=/i.test(wikitext); const backLinkCount = backlinkData.query.backlinks.length; if (isOrphanTagged && backLinkCount >= 1) { const $container = $('<div>').addClass('comrade-container comrade-status'); const $header = $('<div>').addClass('comrade-header'); const $btn = $('<button>').text('Remove orphan tag').click(() => performDeorphan()); $header.append($('<div>').append($('<strong>').text('Status:'), ` Article has ${backLinkCount} backlink(s).`, $btn)); $container.append($header); appendDismiss($container); } if (cleanTitle !== currentTitle) checkAndRenderRedirect(cleanTitle, currentTitle, "R to diacritic", "Diacritic"); checkDomainRedirect(qid, currentTitle); if (qid) { const wikiData = await $.ajax({ url: "https://www.wikidata.org/w/api.php", data: { action: 'wbgetentities', ids: qid, props: 'claims|labels', languages: 'en', format: 'json', origin: '*' }, dataType: 'json' }); const entity = wikiData.entities[qid]; const isHuman = entity?.claims?.P31?.some(c => c.mainsnak?.datavalue?.value?.id === "Q5"); const tClean = currentTitle.replace(/\s*\(.*?\)\s*/g, '').trim(); const nameParts = tClean.split(' '); const hasFamilyNameHatnote = /\{\{family[ _]name[ _]hatnote/i.test(wikitext); const hasShortDesc = /\{\{\s*[Ss]hort description/i.test(wikitext); const dsMatch = wikitext.match(/\{\{(?:DEFAULTSORT|Defaultsort):([^}]+)\}\}/i); const isOrphan = isOrphanTagged && backLinkCount < 1; const primarySurname = hasFamilyNameHatnote ? nameParts[0] : (getSmartSortKey(tClean, entity).split(',')[0] || nameParts[nameParts.length - 1]); let targetSortName = ""; if (isHuman) { const { givens, surnames } = await fetchWikidataNameLabels(entity); const refName = entity.labels?.en?.value || currentTitle; if (dsMatch) { const currentDS = dsMatch[1].trim(); targetSortName = currentDS; if (currentDS.includes(',')) { let [lastPart, firstPart] = currentDS.split(',').map(s => s.trim()); if (firstPart.toLowerCase().endsWith(lastPart.toLowerCase())) { firstPart = firstPart.substring(0, firstPart.length - lastPart.length).trim(); targetSortName = `${fixNameCasing(lastPart, refName)}, ${fixNameCasing(firstPart, refName)}`; renderSortNudge(targetSortName, "Redundant surname in given name field."); } else if (givens.length > 0 && lastPart.split(' ').length > 1) { const misplacedGiven = lastPart.split(' ').find(part => givens.some(gn => gn.toLowerCase() === part.toLowerCase())); if (misplacedGiven) { const newSurname = lastPart.split(' ').filter(p => p !== misplacedGiven).join(' '); targetSortName = `${fixNameCasing(newSurname, refName)}, ${fixNameCasing(misplacedGiven + ' ' + firstPart, refName)}`; renderSortNudge(targetSortName, `Wikidata suggests "${misplacedGiven}" is a given name.`); } } } } else { targetSortName = hasFamilyNameHatnote ? `${nameParts[0]}, ${nameParts.slice(1).join(' ')}` : getSmartSortKey(tClean, entity); const $dsMissing = $('<div>').addClass('comrade-container comrade-nudge'); const $header = $('<div>').addClass('comrade-header'); const $btn = $('<button>').text(`Add: {{DEFAULTSORT:${targetSortName}}}`).click(() => performSortCorrection(targetSortName, "add")); $header.append($('<div>').append($('<strong>').text('DEFAULTSORT:'), ` Tag is missing. `, $btn)); $dsMissing.append($header); appendDismiss($dsMissing); } const longName = getLongNameFromWikitext(wikitext); if (longName && longName.length > tClean.length) { let sortKey = hasFamilyNameHatnote ? `${longName.split(' ')[0]}, ${longName.split(' ').slice(1).join(' ')}` : getSmartSortKey(longName, entity); const rLongWikitext = `#REDIRECT [[${currentTitle}]]\n\n{{Redirect category shell|\n{{R from long name}}\n}}\n{{DEFAULTSORT:${sortKey}}}`; checkAndRenderRedirect(longName, currentTitle, null, "Long name", rLongWikitext); } if (targetSortName) { let targetPage = currentTitle.includes(' (') ? currentTitle.split(' (')[0] : currentTitle; let rCat = targetPage !== currentTitle ? "R from ambiguous sort name" : "R from sort name"; if (targetSortName.includes(',')) { const p = targetSortName.split(','); rCat += `|${p[0].trim().charAt(0).toUpperCase()}|${p[1].trim().charAt(0).toUpperCase()}`; } checkAndRenderRedirect(targetSortName, targetPage, rCat, "Sort name"); } const finalFamilyNames = new Set(); const finalGivenNames = new Set(); surnames.forEach(fn => { if (tClean.toLowerCase().includes(fn.toLowerCase())) { fn.split(' ').forEach(part => finalFamilyNames.add(part)); finalFamilyNames.add(fn); } }); givens.forEach(gn => { if (tClean.toLowerCase().includes(gn.toLowerCase())) finalGivenNames.add(gn); }); if (finalFamilyNames.size === 0 && nameParts.length >= 2) finalFamilyNames.add(nameParts[nameParts.length - 1]); if (finalGivenNames.size === 0 && nameParts.length >= 2) finalGivenNames.add(nameParts[0]); const getPriorityTarget = async (name, type) => { const titles = type === 'surname' ? [`List of people with surname ${name}`, `List of people with the English surname ${name}`, `${name} (surname)`] : [`List of people with given name ${name}`, `${name} (given name)`]; const res = await api.get({ action: 'query', titles: titles.join('|'), formatversion: 2 }); return titles.find(t => res.query.pages.find(pg => pg.title === t && !pg.missing)); }; for (const name of finalGivenNames) { if (name.toLowerCase() === primarySurname.toLowerCase()) continue; const target = await getPriorityTarget(name, 'given'); if (target) await checkNameList(name, 'given name', currentTitle, hasShortDesc, isOrphan, target); } for (const name of finalFamilyNames) { const target = await getPriorityTarget(name, 'surname'); if (target) await checkNameList(name, 'surname', currentTitle, hasShortDesc, isOrphan, target); } } } } catch (err) { console.error("Comrade error:", err); } }); } })(); (function() { if (window.IllWill) return; const STRIKEOUT = true; const HIDE = 'hide'; const IllWill = { Version: "1.1.1", Attribution: 'created by <a target="_blank" href="/wiki/User:Cobaltcigs">cobaltcigs</a>', Summary: "Added interlanguage links using IllWill.js", DataApi: "https://www.wikidata.org/w/api.php", LocalLang: mw.config.get("wgPageContentLanguage"), Disambiguator: / \(.*\)$/, SiteLinks: {}, Config: { MaxLanguages: 5, IgnoreScientific: STRIKEOUT, AutoDiff: true }, css: ` #illwill { clear: both; margin-bottom: 1.5em; border: 1px solid #a2a9b1; padding: 15px; background: #f8f9fa; box-shadow: 0 2px 4px rgba(0,0,0,0.1); } .ill-sitelinks a { display: inline-block; margin-bottom: 3px; font-size: 0.9em; color: #36c; } .ill-size-tag { font-size: 0.8em; color: #72777d; margin-left: 6px; white-space: nowrap; } .illwill-ignore { text-decoration: line-through; color: #72777d; font-size: 0.85em; } .ill-x { width: 35px; text-align: center; } .ill-input, .ill-output { font-family: 'Courier New', monospace; white-space: pre-wrap; font-size: 0.9em; background: #fff; border: 1px solid #eaecf0; padding: 4px; border-radius: 2px; } #ill-buttons { text-align: right; padding: 10px; border-top: 1px solid #a2a9b1; margin-top: 10px; } #ill-buttons button { margin-left: 10px; cursor: pointer; padding: 6px 16px; border-radius: 2px; border: 1px solid #a2a9b1; transition: all 0.2s; } #ill-ok { background: #36c; color: #fff; border-color: #36c !important; font-weight: bold; } #ill-ok:hover { background: #447ff5; } #ill-ok:disabled { background: #eaecf0; color: #72777d; border-color: #c8ccd1 !important; cursor: not-allowed; opacity: 0.7; } #ill-table { width: 100%; border-collapse: collapse; margin-top: 10px; background: white; } #ill-table th { background: #f2f2f2; text-align: left; padding: 8px; border: 1px solid #a2a9b1; } #ill-table td { padding: 8px; border: 1px solid #a2a9b1; vertical-align: top; } #ill-table caption { background: #eaffea; font-weight: bold; padding: 10px; border: 1px solid #a2a9b1; border-bottom: none; font-size: 1.1em; } #ill-help { font-size: 0.85em; color: #54595d; padding: 10px; line-height: 1.4; } .ill-loading-inline { font-style: italic; color: #72777d; font-size: 0.9em; display: block; margin: 5px 0; } `, setup() { if (!["edit", "submit"].includes(mw.config.get('wgAction'))) return; mw.loader.addStyleTag(this.css); const link = mw.util.addPortletLink('p-cactions', '#', 'IllWill', 'ca-illwill', "Add interlanguage links via Wikidata"); if (link) { link.addEventListener('click', (e) => { e.preventDefault(); this.makePanel(); }); } }, norm(s) { if (!s) return ""; const t = s.trim().replace(/[\s_]+/g, " "); return t.charAt(0).toUpperCase() + t.slice(1); }, async getRedLinks($textbox) { const txt = $textbox.textSelection('getContents') || ""; const wl = txt.match(/\[\[[^[\]\n]+\]\]/g); if (!wl) return { reds: [], txt }; const api = new mw.Api(); const textToParse = wl.join("").replace(/\|[^\]]+/g, ""); try { const data = await api.post({ action: 'parse', text: textToParse, contentmodel: 'wikitext', formatversion: 2 }); const tempDiv = document.createElement('div'); tempDiv.innerHTML = data.parse.text; const reds = Array.from(tempDiv.querySelectorAll("a.new")).map(x => { const urlParams = new URLSearchParams(x.href.split('?')[1]); return urlParams.get('title')?.replace(/_/g, " "); }).filter(Boolean); return { reds: [...new Set(reds)], txt }; } catch (e) { return { reds: [], txt }; } }, async makePanel() { const $editform = $('#editform'); const $textbox = $('#wpTextbox1'); $('#illwill').remove(); $editform.hide(); const $wrapper = $('<div id="illwill">Loading redlinks...</div>').insertBefore($editform); const { reds, txt } = await this.getRedLinks($textbox); const wtLinks = []; reds.forEach(title => { const escaped = title.replace(/[.*+?^${}()|[\]\\]/g, '\\$&').replace(/\s/g, "[\\s_]+"); const re = new RegExp("\\[\\[\\s*" + escaped + "\\s*(?:\\|[^\\[\\]]+)?\\]\\]", "ig"); const match = txt.match(re); if (match && !wtLinks.some(z => z.title === title)) { wtLinks.push({ link: match[0], title }); } }); if (!wtLinks.length) { const $back = $('<button>Quit</button>').on('click', () => { $wrapper.remove(); $editform.show(); }); $wrapper.empty().append($('<strong>No valid redlinks found in text.</strong> '), $back); return; } const $table = $(` <table id="ill-table" class="wikitable"> <caption>IllWill.js (v${this.Version})</caption> <thead> <tr> <th class="ill-x"><input type="checkbox" id="ill-select-all" disabled></th> <th>Input link</th> <th>Possible Wikidata matches</th> <th>Sitelinks (top ${this.Config.MaxLanguages} by size)</th> <th>Resulting wikitext</th> </tr> </thead> <tbody></tbody> <tfoot> <tr> <td colspan="3" id="ill-help">Carefully examine possible Wikidata matches.</td> <td colspan="2" id="ill-buttons"> <button id="ill-cancel">Cancel</button> <button id="ill-ok" disabled>Show changes</button> </td> </tr> </tfoot> </table> `); const $tbody = $table.find('tbody'); wtLinks.forEach((item, i) => { $tbody.append(` <tr id="ill-row-${i}" data-index="${i}"> <td class="ill-x"><input type="checkbox" class="ill-row-check" disabled></td> <td class="ill-input">${this.escapeHTML(item.link)}</td> <td class="ill-wd-item"><span class="ill-loading-inline">Searching...</span></td> <td class="ill-sitelinks"></td> <td class="ill-output"></td> </tr> `); }); $wrapper.empty().append($table); const chunkSize = 5; for (let i = 0; i < wtLinks.length; i += chunkSize) { const chunk = wtLinks.slice(i, i + chunkSize); await Promise.all(chunk.map((item, idx) => this.fetchWikidataOptimized(item.title, i + idx))); } $table.on('click', '#ill-cancel', () => { $editform.show(); $wrapper.remove(); }); $table.on('click', '#ill-ok', () => this.onOkButton($editform, $wrapper, $textbox)); $table.on('change', '#ill-select-all', (e) => { const isChecked = $(e.target).is(':checked'); $table.find('.ill-row-check:not(:disabled)').each(function() { $(this).prop('checked', isChecked).trigger('change'); }); }); $table.on('change', '.ill-row-check', (e) => { this.onCheckbox(e); this.updateOkButtonState($table); }); $table.on('change', 'input[type="radio"]', (e) => { this.showSiteLinks(e); }); }, async fetchWikidataOptimized(title, index) { const query = title.replace(this.Disambiguator, ""); const url = `${this.DataApi}?action=wbsearchentities&search=${encodeURIComponent(query)}&language=${this.LocalLang}&limit=5&format=json&origin=*`; try { const resp = await fetch(url); const data = await resp.json(); const results = data.search; const $cell = $(`#ill-row-${index} .ill-wd-item`); if (!results || !results.length) { $cell.html('<span class="ill-na">(no results)</span>'); return; } const entityIds = results.map(r => r.id); await this.fetchEntities(entityIds, index, $cell); } catch (e) { $(`#ill-row-${index} .ill-wd-item`).text("Search failed."); } }, async fetchEntities(ids, rowIndex, $cell) { const url = `${this.DataApi}?action=wbgetentities&ids=${ids.join('|')}&props=labels|descriptions|claims|sitelinks&format=json&origin=*`; try { const resp = await fetch(url); const data = await resp.json(); $cell.empty(); ids.forEach(qNum => { const entity = data.entities[qNum]; if (!entity) return; const isScientific = entity.claims?.P31?.some(s => s.mainsnak?.datavalue?.value?.id === "Q13442814"); if (isScientific && this.Config.IgnoreScientific === HIDE) return; const desc = entity.descriptions?.[this.LocalLang]?.value || entity.descriptions?.en?.value || ""; const label = entity.labels?.[this.LocalLang]?.value || entity.labels?.en?.value || qNum; const isStrikeout = isScientific && this.Config.IgnoreScientific === STRIKEOUT; const $div = $(` <div class="${isStrikeout ? 'illwill-ignore' : ''}"> <input type="radio" name="selection-${rowIndex}" value="${qNum}" id="radio-${qNum}" ${isStrikeout ? 'disabled' : ''}> <label for="radio-${qNum}"> <a href="https://wikidata.org/wiki/${qNum}" target="_blank">${this.escapeHTML(label)}</a>: <span class="ill-desc">${desc ? this.escapeHTML(desc) : '<i>no description</i>'}</span> </label> </div> `); $cell.append($div); this.SiteLinks[qNum] = entity.sitelinks || {}; }); } catch (e) { $cell.text("Detail fetch failed."); } }, updateOkButtonState($table) { const $rows = $table.find('.ill-row-check:not(:disabled)'); const $checkedRows = $rows.filter(':checked'); const anyEnabled = $rows.length > 0; $table.find('#ill-ok').prop('disabled', $checkedRows.length === 0); const $master = $table.find('#ill-select-all'); $master.prop('disabled', !anyEnabled); if (anyEnabled && $rows.length === $checkedRows.length) { $master.prop('checked', true); } else { $master.prop('checked', false); } }, async showSiteLinks(e) { const isManualToggling = e.fromCheckbox || false; const qNum = e.target.value; const $row = $(e.target).closest('tr'); const sitelinks = this.SiteLinks[qNum]; const $checkbox = $row.find('.ill-row-check'); const $sitelinkCell = $row.find('.ill-sitelinks'); const $outputCell = $row.find('.ill-output'); const $table = $('#ill-table'); const effectiveMax = Math.min(Math.max(this.Config.MaxLanguages, 3), 6); const validKeys = Object.keys(sitelinks).filter(k => k.endsWith('wiki') && !k.includes('commons')); $sitelinkCell.html('<span class="ill-loading-inline">Measuring articles...</span>'); $outputCell.empty(); if (!isManualToggling) { $checkbox.prop('disabled', true).prop('checked', false); } const candidates = validKeys.slice(0, 25); const sizeMap = []; await Promise.all(candidates.map(async (key) => { const lang = key.replace('wiki', '').replace(/_/g, '-'); const title = sitelinks[key].title; const endpoint = `https://${lang}.wikipedia.org/w/api.php?action=query&titles=${encodeURIComponent(title)}&prop=info&format=json&origin=*`; try { const res = await fetch(endpoint).then(r => r.json()); const page = Object.values(res.query.pages)[0]; sizeMap.push({ lang, title, length: page.length || 0 }); } catch (err) { sizeMap.push({ lang, title, length: 0 }); } })); sizeMap.sort((a, b) => b.length - a.length); const topLinks = sizeMap.slice(0, effectiveMax); $sitelinkCell.html(topLinks.map(item => { const kbValue = Math.round(item.length / 1024); return `<div><a href="https://${item.lang}.wikipedia.org/wiki/${encodeURIComponent(item.title)}" target="_blank">${item.lang}:${this.escapeHTML(item.title)}</a> <span class="ill-size-tag">(${kbValue} kB)</span></div>`; }).join("")); const inputWikitext = $row.find('.ill-input').text(); const match = inputWikitext.match(/\[\[(.*?)\]\]/); if (match) { const parts = match[1].split('|'); const targetPage = parts[0].trim(); const surfaceName = (parts[1] || parts[0]).trim(); const illLangs = topLinks.map(item => { const isSameTitle = this.norm(item.title) === this.norm(targetPage); return `|${item.lang}|${isSameTitle ? '' : item.title}`; }).join(""); const ltParam = (this.norm(surfaceName) === this.norm(targetPage)) ? "" : `|lt=${surfaceName}`; $outputCell.text(`{{ill|${targetPage}${ltParam}${illLangs}}}`); } $checkbox.prop('disabled', !topLinks.length); if (!isManualToggling) { $checkbox.prop('checked', !!topLinks.length); } this.updateOkButtonState($table); }, onCheckbox(e) { const $row = $(e.target).closest('tr'); const $radio = $row.find('input[type="radio"]:checked'); const isChecked = $(e.target).is(':checked'); if (isChecked) { if ($radio.length) { this.showSiteLinks({ target: $radio[0], fromCheckbox: true }); } } else { $row.find('.ill-sitelinks, .ill-output').empty(); } }, onOkButton($editform, $wrapper, $textbox) { let text = $textbox.textSelection('getContents'); let changed = false; $wrapper.find('.ill-row-check:checked').each(function() { const $row = $(this).closest('tr'); const input = $row.find('.ill-input').text(); const output = $row.find('.ill-output').text(); if (output) { const escapedInput = input.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); text = text.replace(new RegExp(escapedInput, "gi"), output); changed = true; } }); if (changed) { $('#wpSummary').val((i, v) => (v ? v + "; " : "") + this.Summary); $textbox.textSelection('setContents', text); $wrapper.remove(); $editform.show(); if (this.Config.AutoDiff) $('#wpDiff').click(); } }, escapeHTML(str) { return str.replace(/[&<>"']/g, m => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' })[m]); } }; window.IllWill = IllWill; mw.loader.using(['mediawiki.util', 'mediawiki.api', 'jquery.textSelection'], () => { $(() => IllWill.setup()); }); })(); //</nowiki> mqu0dy07k04p0n2muko0gy1lsymjvie 739074 739072 2026-04-22T10:32:45Z Sam Sailor 26820 Test 739074 javascript text/javascript //<nowiki> (function() { var Comrade = Comrade || {}; mw.util.addCSS(` .ambox-Orphan { display: block !important; } .comrade-container { box-shadow: 0 1px 3px rgba(0,0,0,0.1); border-radius: 2px; padding: 10px 15px; margin: 10px 0; display: flex; flex-direction: column; align-items: flex-start; gap: 8px; border: 1px solid #a2a9b1; background: #fcfcfc; line-height: 1.5; } .comrade-header { display: flex; align-items: center; justify-content: space-between; width: 100%; } .comrade-content { display: flex; flex-direction: column; gap: 5px; width: 100%; } .comrade-success { background-color: #d5f5e3 !important; border-left: 5px solid #27ae60 !important; color: #1b5e20 !important; } .comrade-nudge { background: #fff9ea; border-left: 5px solid #f0ad4e; } .comrade-info { background: #eaf3ff; border-left: 5px solid #36c; } .comrade-status { background: #eaf3ff; border-left: 5px solid #36c; } .comrade-container button:not(.comrade-dismiss) { background: #f8f9fa; border: 1px solid #a2a9b1; border-radius: 2px; padding: 2px 10px; cursor: pointer; font-weight: bold; font-size: 0.95em; margin-left: 10px; } .comrade-container button:not(.comrade-dismiss):hover { border-color: #36c; color: #36c; background: #fff; } .comrade-dismiss { background: transparent; border: none; color: #d33; font-weight: bold; cursor: pointer; font-size: 0.9em; } .comrade-dismiss:hover { text-decoration: underline; } .comrade-code-block { background: #f1f1f1; padding: 4px 8px; border-radius: 3px; font-family: monospace; display: inline-block; margin-top: 4px; } `); function appendDismiss($el) { $('<button>').addClass('comrade-dismiss').text('Dismiss').click(function() { $(this).closest('.comrade-container').fadeOut(); }).appendTo($el.find('.comrade-header')); $("#siteSub").after($el); } async function checkAndRenderRedirect(redirTitle, targetTitle, rCategory, labelText, customWikitext) { const api = new mw.Api(); const res = await api.get({ action: 'query', titles: redirTitle, formatversion: 2 }); if (res.query.pages[0].missing) { const safeId = "comrade-redir-" + btoa(unescape(encodeURIComponent(redirTitle))).replace(/=/g, ""); const $container = $('<div>').addClass('comrade-container comrade-info').attr('id', safeId); const $header = $('<div>').addClass('comrade-header'); const summary = `Created redirect from ${labelText.toLowerCase()} to [[${targetTitle}]]`; const $btn = $('<button>').text('Create redirect').click(() => createModernRedirect(redirTitle, targetTitle, rCategory, summary, safeId, customWikitext)); $header.append($('<div>').append($('<strong>').text(`${labelText}: `), `Create redirect from `, $('<code>').text(redirTitle), $btn)); $container.append($header); appendDismiss($container); } } async function checkDomainRedirect(qid, currentTitle) { let domainCandidate = ""; if (qid) { try { const res = await $.ajax({ url: "https://www.wikidata.org/w/api.php", data: { action: 'wbgetclaims', entity: qid, property: 'P856', format: 'json', origin: '*' } }); if (res.claims?.P856) { domainCandidate = res.claims.P856[0].mainsnak.datavalue.value; } } catch (e) { console.log("Comrade: Wikidata API call failed."); } } if (!domainCandidate) { domainCandidate = $(".infobox .url a").last().attr("href") || $(".official-website a").first().attr("href"); } if (domainCandidate) { try { const url = new URL(domainCandidate); let domain = url.hostname.replace(/^www\d*\./, ""); if (domain.includes(".") && url.pathname === "/") { const citationURL = '/api/rest_v1/data/citation/mediawiki/' + encodeURIComponent(domainCandidate); $.ajax({ url: citationURL, method: 'GET', success: function() { checkAndRenderRedirect(domain, currentTitle, "R from domain name", "Domain"); } }); } } catch (e) { console.log("Comrade: Error parsing URL object."); } } } async function checkNameList(name, type, currentTitle, hasShortDesc, isOrphan) { const api = new mw.Api(); const candidates = [`${name} (${type})`, `${name} (${type.toLowerCase()})`, `${name} (name)`, name]; const checked = new Set(); for (const title of candidates) { if (checked.has(title)) continue; checked.add(title); const res = await api.get({ action: 'query', prop: 'revisions', titles: title, rvprop: 'content', formatversion: 2, redirects: 0 }); const page = res.query.pages[0]; if (page && !page.missing) { const text = page.revisions[0].content; const resolvedTitle = page.title; const isNameMatch = /\{\{(Surname|Hndis|Given[ _]name|Forename|Givenname)/i.test(text); const isNameDab = /\{\{(Disambiguation|Dab|Disambig)(?:[^}]*\|(surname|surnames|given[ _]name|given[ _]names)|(?:\s*\}\}))/i.test(text); if (isNameMatch || isNameDab) { const escapedTitle = currentTitle.replace(/[.*+?^${}()|[\]\\]/g, '\\$&').replace(/ /g, '[ _]'); const alreadyListed = new RegExp('(\\[\\[|\\{\\{anbl\\|[ _]*|\\|)' + escapedTitle, 'i').test(text); if (alreadyListed) break; const $container = $('<div>').addClass('comrade-container'); const $header = $('<div>').addClass('comrade-header'); const $content = $('<div>').addClass('comrade-content'); if (isOrphan) { $container.addClass('comrade-nudge'); $header.append($('<strong>').text('Comrade nudge:')); } else { $container.addClass('comrade-info'); $header.append($('<strong>').text('Informative:')); } $content.append($('<span>').append(`${type.charAt(0).toUpperCase() + type.slice(1)} not listed at `, $('<a>').attr({ href: mw.util.getUrl(resolvedTitle), target: '_blank' }).text(resolvedTitle), "; should it be?")); const snippet = '* {{anbl|' + currentTitle + '}}'; const $snippetWrapper = $('<div>').css({ 'display': 'flex', 'align-items': 'center', 'gap': '10px', 'margin-top': '4px' }); const $instructionSpan = $('<span>').append('If the Short description is good, consider adding ', $('<code>').text(snippet).css({ 'background-color': '#f8f9fa', 'border': '1px solid #eaecf0', 'border-radius': '2px', 'padding': '1px 4px' })); const $copyBtn = $('<button>').text('Copy').css('margin-left', '0').click(function() { navigator.clipboard.writeText(snippet).then(() => { const $this = $(this); const originalText = $this.text(); $this.text('Copied!').prop('disabled', true); setTimeout(() => { $this.text(originalText).prop('disabled', false); }, 1500); }); }); $snippetWrapper.append($instructionSpan, $copyBtn); $content.append($snippetWrapper); if (!hasShortDesc) { $content.append($('<span>').css({ 'color': '#d33', 'font-weight': 'bold', 'margin-top': '5px' }).text('⚠️ Missing short description: Please add a concise one before listing.')); } $container.append($header, $content); appendDismiss($container); break; } } } } async function createModernRedirect(redirTitle, targetTitle, rCategory, customSummary, elementId, customWikitext) { const api = new mw.Api(); const content = customWikitext || `#REDIRECT [[${targetTitle}]]\n\n{{Redirect category shell|\n{{${rCategory}}}\n}}`; const summary = customSummary || `Created redirect from [[${redirTitle}]]`; return api.postWithToken('csrf', { action: 'edit', title: redirTitle, text: content, summary: summary, createonly: true }).done(() => { mw.notify("Redirect created!", { type: 'success', tag: 'comrade', classes: ['comrade-success'] }); $(`#${elementId}`).fadeOut(); }); } function getSmartSortKey(fullName, entity) { const countryIds = entity.claims?.P27?.map(c => c.mainsnak?.datavalue?.value?.id) || []; const locationIds = entity.claims?.P17?.map(c => c.mainsnak?.datavalue?.value?.id) || []; const placeIds = [...(entity.claims?.P19 || []), ...(entity.claims?.P119 || [])].map(c => c.mainsnak?.datavalue?.value?.id).filter(Boolean); const allRelevantIds = [...countryIds, ...locationIds, ...placeIds]; const birthYear = parseInt(entity.claims?.P569?.[0]?.mainsnak?.datavalue?.value?.time?.match(/[+-](\d{4})/)?.[1]) || 2026; if (fullName.startsWith("Saint ")) return fullName.replace("Saint ", ""); const arabicParticles = /\b(Abu|Abd|Abdel|Abdul|ben|bin|bint)\b/i; if (fullName.match(arabicParticles)) { if (birthYear > 1900) { const parts = fullName.split(' '); const binIndex = parts.findIndex(p => p.toLowerCase() === 'bin' || p.toLowerCase() === 'ben'); if (binIndex > 0) return parts.slice(binIndex).join(' ') + ', ' + parts.slice(0, binIndex).join(' '); } else { return fullName; } } const eastAsianQids = ["Q148", "Q184", "Q884", "Q424", "Q881", "Q17"]; if (allRelevantIds.some(id => eastAsianQids.includes(id))) { if (allRelevantIds.includes("Q17") && birthYear > 1885) return westernSort(fullName); const parts = fullName.split(' '); if (parts.length > 1) return `${parts[0]}, ${parts.slice(1).join(' ')}`; } return westernSort(fullName); } function westernSort(name) { let cleanName = name; if (name.startsWith("O'")) cleanName = name.replace("O'", "O"); const parts = cleanName.split(' '); if (parts.length < 2) return cleanName; const surname = parts.pop(); if (["Jr.", "Jr", "III", "II", "Sr.", "Sr"].includes(surname)) { const actualSurname = parts.pop(); return `${actualSurname}, ${parts.join(' ')} ${surname}`; } return `${surname}, ${parts.join(' ')}`; } async function performDeorphan() { const api = new mw.Api(); await api.edit(mw.config.get('wgPageName'), function(rev) { let text = rev.content; const summary = 'Article has backlinks; removed [[Template:Orphan|{{Orphan}}]]'; text = text.replace(/\{\{Orphan\s*(?:\|[^}]*)?\}\}\s*/gi, ''); text = text.replace(/(\{\{Multiple[ _]issues\s*)\|\s*\|/gi, '$1|'); text = replaceMI(text); text = text.replace(/\n{3,}/g, '\n\n').trim(); return { text, summary, minor: true }; }); mw.notify('Orphan tag removed!', { type: 'success', tag: 'comrade', classes: ['comrade-success'] }); setTimeout(() => location.reload(), 700); } function replaceMI(text) { const miStart = /\{\{Multiple[ _]issues\s*\|/gi; let result = ''; let lastIndex = 0; let match; while ((match = miStart.exec(text)) !== null) { const start = match.index; result += text.slice(lastIndex, start); let depth = 0; let i = start; while (i < text.length) { if (text[i] === '{' && text[i + 1] === '{') { depth++; i += 2; } else if (text[i] === '}' && text[i + 1] === '}') { depth--; i += 2; if (depth === 0) break; } else { i++; } } const end = i; const full = text.slice(start, end); const pipeIdx = full.indexOf('|'); const inner = full.slice(pipeIdx + 1, full.length - 2).trim(); const topLevel = extractTopLevelTemplates(inner); if (topLevel.length === 0) { result += ''; } else if (topLevel.length === 1) { result += topLevel[0].trim(); } else { result += full; } lastIndex = end; miStart.lastIndex = lastIndex; } result += text.slice(lastIndex); return result; } function extractTopLevelTemplates(inner) { const templates = []; let i = 0; while (i < inner.length) { if (inner[i] === '{' && inner[i + 1] === '{') { let depth = 0; const start = i; while (i < inner.length) { if (inner[i] === '{' && inner[i + 1] === '{') { depth++; i += 2; } else if (inner[i] === '}' && inner[i + 1] === '}') { depth--; i += 2; if (depth === 0) break; } else { i++; } } templates.push(inner.slice(start, i)); } else { i++; } } return templates; } async function performSortCorrection(newName, type) { const api = new mw.Api(); const title = mw.config.get("wgPageName"); try { const data = await api.get({ action: 'query', prop: 'revisions', titles: title, rvprop: 'content', formatversion: 2 }); let content = data.query.pages[0].revisions[0].content; const dsRegex = /\{\{(?:DEFAULTSORT|Defaultsort):[^}]+\}\}/i; const newTag = `{{DEFAULTSORT:${newName}}}`; let actionDesc = type === "add" ? "added" : "corrected"; if (dsRegex.test(content)) { content = content.replace(dsRegex, newTag); } else { const catRegex = /\[\[Category:/i; if (catRegex.test(content)) { content = content.replace(catRegex, `${newTag}\n[[Category:`); } else { content += `\n\n${newTag}`; } } await api.postWithToken('csrf', { action: 'edit', title: title, text: content, summary: `Setting DEFAULTSORT to ${newName}`, nocreate: true }); mw.notify(`DEFAULTSORT ${actionDesc} to ${newName}!`, { title: 'Comrade Success', type: 'success' }); setTimeout(() => location.reload(), 700); } catch (err) { mw.notify('Failed to save DEFAULTSORT.', { type: 'error' }); } } function stripDiacritics(str) { return str.normalize("NFD").replace(/[\u0300-\u036f]/g, ""); } function renderSortNudge(target, reason) { const $dsNudge = $('<div>').addClass('comrade-container comrade-nudge'); const $header = $('<div>').addClass('comrade-header'); const $btn = $('<button>').text(`Correct to: ${target}`).click(() => performSortCorrection(target, "format")); $header.append($('<div>').append($('<strong>').text('DEFAULTSORT:'), ` ${reason} `, $btn)); $dsNudge.append($header); appendDismiss($dsNudge); } async function fetchWikidataNameLabels(entity) { const familyIds = entity.claims?.P734?.map(c => c.mainsnak.datavalue.value.id) || []; const givenIds = entity.claims?.P735?.map(c => c.mainsnak.datavalue.value.id) || []; const allNameIds = [...new Set([...familyIds, ...givenIds])]; if (allNameIds.length === 0) return { givens: [], surnames: [] }; const nameData = await $.ajax({ url: "https://www.wikidata.org/w/api.php", data: { action: 'wbgetentities', ids: allNameIds.join('|'), props: 'labels', languages: 'en', format: 'json', origin: '*' }, dataType: 'json' }); return { givens: givenIds.map(id => nameData.entities[id]?.labels?.en?.value).filter(Boolean), surnames: familyIds.map(id => nameData.entities[id]?.labels?.en?.value).filter(Boolean) }; } function fixNameCasing(part, referenceName) { return part.split(' ').map(word => { const match = referenceName.match(new RegExp(`\\b${word}\\b`, 'i')); if (match) return match[0]; return referenceName.split(' ').find(tWord => word.toLowerCase().startsWith(tWord.toLowerCase()) || tWord.toLowerCase().startsWith(word.toLowerCase())) || word; }).join(' '); } function getLongNameFromWikitext(wikitext) { const firstLine = wikitext.split('\n').find(l => l.includes("'''")); if (!firstLine) return null; const boldMatch = firstLine.match(/'''(.+?)'''/); if (!boldMatch) return null; return boldMatch[1].replace(/\s*([“"«《„‹「『'].+?[”"»》”›」』']|\([^)\n]*\))\s*/g, ' ').replace(/\s+/g, ' ').trim(); } if (mw.config.get("wgDBname") === "enwiki" && mw.config.get("wgUserId") === 19244234 && mw.config.get("wgNamespaceNumber") === 0 && mw.config.get("wgAction") === "view") { $(document).ready(async function() { const api = new mw.Api(); const qid = mw.config.get("wgWikibaseItemId"); try { const [pageData, backlinkData] = await Promise.all([ api.get({ action: 'query', prop: 'revisions', titles: mw.config.get("wgPageName"), rvprop: 'content', formatversion: 2 }), api.get({ action: 'query', list: 'backlinks', blfilterredir: 'nonredirects', bllimit: 50, blnamespace: 0, bltitle: mw.config.get("wgPageName"), formatversion: 2 }) ]); const page = pageData.query.pages[0]; if (!page || page.missing || !page.revisions) return; const wikitext = page.revisions[0].content; const currentTitle = mw.config.get("wgTitle"); const cleanTitle = stripDiacritics(currentTitle); const isOrphanTagged = /\{\{\s*(Orphan|Do-attempt|Lonely|Orp|Orphaned article)/i.test(wikitext) || /\| *orphan *=/i.test(wikitext); const backLinkCount = backlinkData.query.backlinks.length; if (isOrphanTagged && backLinkCount >= 1) { const $container = $('<div>').addClass('comrade-container comrade-status'); const $header = $('<div>').addClass('comrade-header'); const $btn = $('<button>').text('Remove orphan tag').click(() => performDeorphan()); $header.append($('<div>').append($('<strong>').text('Status:'), ` Article has ${backLinkCount} backlink(s).`, $btn)); $container.append($header); appendDismiss($container); } if (cleanTitle !== currentTitle) checkAndRenderRedirect(cleanTitle, currentTitle, "R to diacritic", "Diacritic"); checkDomainRedirect(qid, currentTitle); if (qid) { const wikiData = await $.ajax({ url: "https://www.wikidata.org/w/api.php", data: { action: 'wbgetentities', ids: qid, props: 'claims|labels', languages: 'en', format: 'json', origin: '*' }, dataType: 'json' }); const entity = wikiData.entities[qid]; const isHuman = entity?.claims?.P31?.some(c => c.mainsnak?.datavalue?.value?.id === "Q5"); const tClean = currentTitle.replace(/\s*\(.*?\)\s*/g, '').trim(); const nameParts = tClean.split(' '); const hasFamilyNameHatnote = /\{\{family[ _]name[ _]hatnote/i.test(wikitext); const hasShortDesc = /\{\{\s*[Ss]hort description/i.test(wikitext); const dsMatch = wikitext.match(/\{\{(?:DEFAULTSORT|Defaultsort):([^}]+)\}\}/i); const isOrphan = isOrphanTagged && backLinkCount < 1; const primarySurname = hasFamilyNameHatnote ? nameParts[0] : (getSmartSortKey(tClean, entity).split(',')[0] || nameParts[nameParts.length - 1]); let targetSortName = ""; if (isHuman) { const { givens, surnames } = await fetchWikidataNameLabels(entity); const refName = entity.labels?.en?.value || currentTitle; if (dsMatch) { const currentDS = dsMatch[1].trim(); targetSortName = currentDS; if (currentDS.includes(',')) { let [lastPart, firstPart] = currentDS.split(',').map(s => s.trim()); if (firstPart.toLowerCase().endsWith(lastPart.toLowerCase())) { firstPart = firstPart.substring(0, firstPart.length - lastPart.length).trim(); targetSortName = `${fixNameCasing(lastPart, refName)}, ${fixNameCasing(firstPart, refName)}`; renderSortNudge(targetSortName, "Redundant surname in given name field."); } else if (givens.length > 0 && lastPart.split(' ').length > 1) { const misplacedGiven = lastPart.split(' ').find(part => givens.some(gn => gn.toLowerCase() === part.toLowerCase())); if (misplacedGiven) { const newSurname = lastPart.split(' ').filter(p => p !== misplacedGiven).join(' '); targetSortName = `${fixNameCasing(newSurname, refName)}, ${fixNameCasing(misplacedGiven + ' ' + firstPart, refName)}`; renderSortNudge(targetSortName, `Wikidata suggests "${misplacedGiven}" is a given name.`); } } } } else { targetSortName = hasFamilyNameHatnote ? `${nameParts[0]}, ${nameParts.slice(1).join(' ')}` : getSmartSortKey(tClean, entity); const $dsMissing = $('<div>').addClass('comrade-container comrade-nudge'); const $header = $('<div>').addClass('comrade-header'); const $btn = $('<button>').text(`Add: {{DEFAULTSORT:${targetSortName}}}`).click(() => performSortCorrection(targetSortName, "add")); $header.append($('<div>').append($('<strong>').text('DEFAULTSORT:'), ` Tag is missing. `, $btn)); $dsMissing.append($header); appendDismiss($dsMissing); } const longName = getLongNameFromWikitext(wikitext); if (longName && longName.length > tClean.length) { let sortKey = hasFamilyNameHatnote ? `${longName.split(' ')[0]}, ${longName.split(' ').slice(1).join(' ')}` : getSmartSortKey(longName, entity); const rLongWikitext = `#REDIRECT [[${currentTitle}]]\n\n{{Redirect category shell|\n{{R from long name}}\n}}\n{{DEFAULTSORT:${sortKey}}}`; checkAndRenderRedirect(longName, currentTitle, null, "Long name", rLongWikitext); } if (targetSortName) { let targetPage = currentTitle.includes(' (') ? currentTitle.split(' (')[0] : currentTitle; let rCat = targetPage !== currentTitle ? "R from ambiguous sort name" : "R from sort name"; if (targetSortName.includes(',')) { const p = targetSortName.split(','); rCat += `|${p[0].trim().charAt(0).toUpperCase()}|${p[1].trim().charAt(0).toUpperCase()}`; } checkAndRenderRedirect(targetSortName, targetPage, rCat, "Sort name"); } const finalFamilyNames = new Set(); const finalGivenNames = new Set(); surnames.forEach(fn => { if (tClean.toLowerCase().includes(fn.toLowerCase())) { fn.split(' ').forEach(part => finalFamilyNames.add(part)); finalFamilyNames.add(fn); } }); givens.forEach(gn => { if (tClean.toLowerCase().includes(gn.toLowerCase())) finalGivenNames.add(gn); }); if (finalFamilyNames.size === 0 && nameParts.length >= 2) finalFamilyNames.add(nameParts[nameParts.length - 1]); if (finalGivenNames.size === 0 && nameParts.length >= 2) finalGivenNames.add(nameParts[0]); const getPriorityTarget = async (name, type) => { const titles = type === 'surname' ? [`List of people with surname ${name}`, `List of people with the English surname ${name}`, `${name} (surname)`] : [`List of people with given name ${name}`, `${name} (given name)`]; const res = await api.get({ action: 'query', titles: titles.join('|'), formatversion: 2 }); return titles.find(t => res.query.pages.find(pg => pg.title === t && !pg.missing)); }; for (const name of finalGivenNames) { if (name.toLowerCase() === primarySurname.toLowerCase()) continue; const target = await getPriorityTarget(name, 'given'); if (target) await checkNameList(name, 'given name', currentTitle, hasShortDesc, isOrphan, target); } for (const name of finalFamilyNames) { const target = await getPriorityTarget(name, 'surname'); if (target) await checkNameList(name, 'surname', currentTitle, hasShortDesc, isOrphan, target); } } } } catch (err) { console.error("Comrade error:", err); } }); } })(); (function() { if (window.IllWill) return; const STRIKEOUT = true; const HIDE = 'hide'; const IllWill = { Version: "1.1.1", Attribution: 'created by <a target="_blank" href="/wiki/User:Cobaltcigs">cobaltcigs</a>', Summary: "Added interlanguage links using IllWill.js", DataApi: "https://www.wikidata.org/w/api.php", LocalLang: mw.config.get("wgPageContentLanguage"), Disambiguator: / \(.*\)$/, SiteLinks: {}, Config: { MaxLanguages: 5, IgnoreScientific: STRIKEOUT, AutoDiff: true }, css: ` #illwill { clear: both; margin-bottom: 1.5em; border: 1px solid #a2a9b1; padding: 15px; background: #f8f9fa; box-shadow: 0 2px 4px rgba(0,0,0,0.1); } .ill-sitelinks a { display: inline-block; margin-bottom: 3px; font-size: 0.9em; color: #36c; } .ill-size-tag { font-size: 0.8em; color: #72777d; margin-left: 6px; white-space: nowrap; } .illwill-ignore { text-decoration: line-through; color: #72777d; font-size: 0.85em; } .ill-x { width: 35px; text-align: center; } .ill-input, .ill-output { font-family: 'Courier New', monospace; white-space: pre-wrap; font-size: 0.9em; background: #fff; border: 1px solid #eaecf0; padding: 4px; border-radius: 2px; } #ill-buttons { text-align: right; padding: 10px; border-top: 1px solid #a2a9b1; margin-top: 10px; } #ill-buttons button { margin-left: 10px; cursor: pointer; padding: 6px 16px; border-radius: 2px; border: 1px solid #a2a9b1; transition: all 0.2s; } #ill-ok { background: #36c; color: #fff; border-color: #36c !important; font-weight: bold; } #ill-ok:hover { background: #447ff5; } #ill-ok:disabled { background: #eaecf0; color: #72777d; border-color: #c8ccd1 !important; cursor: not-allowed; opacity: 0.7; } #ill-table { width: 100%; border-collapse: collapse; margin-top: 10px; background: white; } #ill-table th { background: #f2f2f2; text-align: left; padding: 8px; border: 1px solid #a2a9b1; } #ill-table td { padding: 8px; border: 1px solid #a2a9b1; vertical-align: top; } #ill-table caption { background: #eaffea; font-weight: bold; padding: 10px; border: 1px solid #a2a9b1; border-bottom: none; font-size: 1.1em; } #ill-help { font-size: 0.85em; color: #54595d; padding: 10px; line-height: 1.4; } .ill-loading-inline { font-style: italic; color: #72777d; font-size: 0.9em; display: block; margin: 5px 0; } `, setup() { if (!["edit", "submit"].includes(mw.config.get('wgAction'))) return; mw.loader.addStyleTag(this.css); const link = mw.util.addPortletLink('p-cactions', '#', 'IllWill', 'ca-illwill', "Add interlanguage links via Wikidata"); if (link) { link.addEventListener('click', (e) => { e.preventDefault(); this.makePanel(); }); } }, norm(s) { if (!s) return ""; const t = s.trim().replace(/[\s_]+/g, " "); return t.charAt(0).toUpperCase() + t.slice(1); }, async getRedLinks($textbox) { const txt = $textbox.textSelection('getContents') || ""; const wl = txt.match(/\[\[[^[\]\n]+\]\]/g); if (!wl) return { reds: [], txt }; const api = new mw.Api(); const textToParse = wl.join("").replace(/\|[^\]]+/g, ""); try { const data = await api.post({ action: 'parse', text: textToParse, contentmodel: 'wikitext', formatversion: 2 }); const tempDiv = document.createElement('div'); tempDiv.innerHTML = data.parse.text; const reds = Array.from(tempDiv.querySelectorAll("a.new")).map(x => { const urlParams = new URLSearchParams(x.href.split('?')[1]); return urlParams.get('title')?.replace(/_/g, " "); }).filter(Boolean); return { reds: [...new Set(reds)], txt }; } catch (e) { return { reds: [], txt }; } }, async makePanel() { const $editform = $('#editform'); const $textbox = $('#wpTextbox1'); $('#illwill').remove(); $editform.hide(); const $wrapper = $('<div id="illwill">Loading redlinks...</div>').insertBefore($editform); const { reds, txt } = await this.getRedLinks($textbox); const wtLinks = []; reds.forEach(title => { const escaped = title.replace(/[.*+?^${}()|[\]\\]/g, '\\$&').replace(/\s/g, "[\\s_]+"); const re = new RegExp("\\[\\[\\s*" + escaped + "\\s*(?:\\|[^\\[\\]]+)?\\]\\]", "ig"); const match = txt.match(re); if (match && !wtLinks.some(z => z.title === title)) { wtLinks.push({ link: match[0], title }); } }); if (!wtLinks.length) { const $back = $('<button>Quit</button>').on('click', () => { $wrapper.remove(); $editform.show(); }); $wrapper.empty().append($('<strong>No valid redlinks found in text.</strong> '), $back); return; } const $table = $(` <table id="ill-table" class="wikitable"> <caption>IllWill.js (v${this.Version})</caption> <thead> <tr> <th class="ill-x"><input type="checkbox" id="ill-select-all" disabled></th> <th>Input link</th> <th>Possible Wikidata matches</th> <th>Sitelinks (top ${this.Config.MaxLanguages} by size)</th> <th>Resulting wikitext</th> </tr> </thead> <tbody></tbody> <tfoot> <tr> <td colspan="3" id="ill-help">Carefully examine possible Wikidata matches.</td> <td colspan="2" id="ill-buttons"> <button id="ill-cancel">Cancel</button> <button id="ill-ok" disabled>Show changes</button> </td> </tr> </tfoot> </table> `); const $tbody = $table.find('tbody'); wtLinks.forEach((item, i) => { $tbody.append(` <tr id="ill-row-${i}" data-index="${i}"> <td class="ill-x"><input type="checkbox" class="ill-row-check" disabled></td> <td class="ill-input">${this.escapeHTML(item.link)}</td> <td class="ill-wd-item"><span class="ill-loading-inline">Searching...</span></td> <td class="ill-sitelinks"></td> <td class="ill-output"></td> </tr> `); }); $wrapper.empty().append($table); const chunkSize = 5; for (let i = 0; i < wtLinks.length; i += chunkSize) { const chunk = wtLinks.slice(i, i + chunkSize); await Promise.all(chunk.map((item, idx) => this.fetchWikidataOptimized(item.title, i + idx))); } $table.on('click', '#ill-cancel', () => { $editform.show(); $wrapper.remove(); }); $table.on('click', '#ill-ok', () => this.onOkButton($editform, $wrapper, $textbox)); $table.on('change', '#ill-select-all', (e) => { const isChecked = $(e.target).is(':checked'); $table.find('.ill-row-check:not(:disabled)').each(function() { $(this).prop('checked', isChecked).trigger('change'); }); }); $table.on('change', '.ill-row-check', (e) => { this.onCheckbox(e); this.updateOkButtonState($table); }); $table.on('change', 'input[type="radio"]', (e) => { this.showSiteLinks(e); }); }, async fetchWikidataOptimized(title, index) { const query = title.replace(this.Disambiguator, ""); const url = `${this.DataApi}?action=wbsearchentities&search=${encodeURIComponent(query)}&language=${this.LocalLang}&limit=5&format=json&origin=*`; try { const resp = await fetch(url); const data = await resp.json(); const results = data.search; const $cell = $(`#ill-row-${index} .ill-wd-item`); if (!results || !results.length) { $cell.html('<span class="ill-na">(no results)</span>'); return; } const entityIds = results.map(r => r.id); await this.fetchEntities(entityIds, index, $cell); } catch (e) { $(`#ill-row-${index} .ill-wd-item`).text("Search failed."); } }, async fetchEntities(ids, rowIndex, $cell) { const url = `${this.DataApi}?action=wbgetentities&ids=${ids.join('|')}&props=labels|descriptions|claims|sitelinks&format=json&origin=*`; try { const resp = await fetch(url); const data = await resp.json(); $cell.empty(); ids.forEach(qNum => { const entity = data.entities[qNum]; if (!entity) return; const isScientific = entity.claims?.P31?.some(s => s.mainsnak?.datavalue?.value?.id === "Q13442814"); if (isScientific && this.Config.IgnoreScientific === HIDE) return; const desc = entity.descriptions?.[this.LocalLang]?.value || entity.descriptions?.en?.value || ""; const label = entity.labels?.[this.LocalLang]?.value || entity.labels?.en?.value || qNum; const isStrikeout = isScientific && this.Config.IgnoreScientific === STRIKEOUT; const $div = $(` <div class="${isStrikeout ? 'illwill-ignore' : ''}"> <input type="radio" name="selection-${rowIndex}" value="${qNum}" id="radio-${qNum}" ${isStrikeout ? 'disabled' : ''}> <label for="radio-${qNum}"> <a href="https://wikidata.org/wiki/${qNum}" target="_blank">${this.escapeHTML(label)}</a>: <span class="ill-desc">${desc ? this.escapeHTML(desc) : '<i>no description</i>'}</span> </label> </div> `); $cell.append($div); this.SiteLinks[qNum] = entity.sitelinks || {}; }); } catch (e) { $cell.text("Detail fetch failed."); } }, updateOkButtonState($table) { const $rows = $table.find('.ill-row-check:not(:disabled)'); const $checkedRows = $rows.filter(':checked'); const anyEnabled = $rows.length > 0; $table.find('#ill-ok').prop('disabled', $checkedRows.length === 0); const $master = $table.find('#ill-select-all'); $master.prop('disabled', !anyEnabled); if (anyEnabled && $rows.length === $checkedRows.length) { $master.prop('checked', true); } else { $master.prop('checked', false); } }, async showSiteLinks(e) { const isManualToggling = e.fromCheckbox || false; const qNum = e.target.value; const $row = $(e.target).closest('tr'); const sitelinks = this.SiteLinks[qNum]; const $checkbox = $row.find('.ill-row-check'); const $sitelinkCell = $row.find('.ill-sitelinks'); const $outputCell = $row.find('.ill-output'); const $table = $('#ill-table'); const effectiveMax = Math.min(Math.max(this.Config.MaxLanguages, 3), 6); const validKeys = Object.keys(sitelinks).filter(k => k.endsWith('wiki') && !k.includes('commons')); $sitelinkCell.html('<span class="ill-loading-inline">Measuring articles...</span>'); $outputCell.empty(); if (!isManualToggling) { $checkbox.prop('disabled', true).prop('checked', false); } const candidates = validKeys.slice(0, 25); const sizeMap = []; await Promise.all(candidates.map(async (key) => { const lang = key.replace('wiki', '').replace(/_/g, '-'); const title = sitelinks[key].title; const endpoint = `https://${lang}.wikipedia.org/w/api.php?action=query&titles=${encodeURIComponent(title)}&prop=info&format=json&origin=*`; try { const res = await fetch(endpoint).then(r => r.json()); const page = Object.values(res.query.pages)[0]; sizeMap.push({ lang, title, length: page.length || 0 }); } catch (err) { sizeMap.push({ lang, title, length: 0 }); } })); sizeMap.sort((a, b) => b.length - a.length); const topLinks = sizeMap.slice(0, effectiveMax); $sitelinkCell.html(topLinks.map(item => { const kbValue = Math.round(item.length / 1024); return `<div><a href="https://${item.lang}.wikipedia.org/wiki/${encodeURIComponent(item.title)}" target="_blank">${item.lang}:${this.escapeHTML(item.title)}</a> <span class="ill-size-tag">(${kbValue} kB)</span></div>`; }).join("")); const inputWikitext = $row.find('.ill-input').text(); const match = inputWikitext.match(/\[\[(.*?)\]\]/); if (match) { const parts = match[1].split('|'); const targetPage = parts[0].trim(); const surfaceName = (parts[1] || parts[0]).trim(); const illLangs = topLinks.map(item => { const isSameTitle = this.norm(item.title) === this.norm(targetPage); return `|${item.lang}|${isSameTitle ? '' : item.title}`; }).join(""); const ltParam = (this.norm(surfaceName) === this.norm(targetPage)) ? "" : `|lt=${surfaceName}`; $outputCell.text(`{{ill|${targetPage}${ltParam}${illLangs}}}`); } $checkbox.prop('disabled', !topLinks.length); if (!isManualToggling) { $checkbox.prop('checked', !!topLinks.length); } this.updateOkButtonState($table); }, onCheckbox(e) { const $row = $(e.target).closest('tr'); const $radio = $row.find('input[type="radio"]:checked'); const isChecked = $(e.target).is(':checked'); if (isChecked) { if ($radio.length) { this.showSiteLinks({ target: $radio[0], fromCheckbox: true }); } } else { $row.find('.ill-sitelinks, .ill-output').empty(); } }, onOkButton($editform, $wrapper, $textbox) { let text = $textbox.textSelection('getContents'); let changed = false; $wrapper.find('.ill-row-check:checked').each(function() { const $row = $(this).closest('tr'); const input = $row.find('.ill-input').text(); const output = $row.find('.ill-output').text(); if (output) { const escapedInput = input.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); text = text.replace(new RegExp(escapedInput, "gi"), output); changed = true; } }); if (changed) { $('#wpSummary').val((i, v) => (v ? v + "; " : "") + this.Summary); $textbox.textSelection('setContents', text); $wrapper.remove(); $editform.show(); if (this.Config.AutoDiff) $('#wpDiff').click(); } }, escapeHTML(str) { return str.replace(/[&<>"']/g, m => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' })[m]); } }; window.IllWill = IllWill; mw.loader.using(['mediawiki.util', 'mediawiki.api', 'jquery.textSelection'], () => { $(() => IllWill.setup()); }); })(); (function() { 'use strict'; const config = { enableNS14: true, rootWhitelists: ['Materials'], userWhitelist: "" }; const categoryDataCache = {}; let scanProgress = 0; let totalToScan = 0; async function verifyTreeMembership() { if (!config.enableNS14) return false; const api = new mw.Api(); const currentTitle = mw.config.get("wgPageName").replace(/_/g, ' '); const fullRoots = config.rootWhitelists.concat(config.userWhitelist.split(',').map(s => s.trim()).filter(s => s)).map(cat => (cat.startsWith('Category:') ? cat : `Category:${cat}`)); if (fullRoots.includes(currentTitle)) return true; let categoriesToTable = mw.config.get('wgCategories') || []; let checked = new Set(); while (categoriesToTable.length > 0) { if (categoriesToTable.some(cat => fullRoots.includes('Category:' + cat))) { return true; } categoriesToTable.forEach(cat => checked.add(cat)); try { const res = await api.get({ formatversion: 2, prop: 'categories', titles: categoriesToTable.map(c => 'Category:' + c), cllimit: 'max' }); let nextBatch = []; if (res.query && res.query.pages) { res.query.pages.forEach(page => { if (page.categories) { page.categories.forEach(parent => { const parentName = parent.title.substring('Category:'.length); if (!checked.has(parentName)) { nextBatch.push(parentName); } }); } }); } categoriesToTable = [...new Set(nextBatch)]; } catch (e) { return false; } } return false; } function getChemboxBlock(wikitext) { const chemboxRegex = /\{\{\s*Chembox[\s_]*(?:[^{}]|\{\{(?:[^{}]|\{\{[^{}]*\}\})*\}\})*\}\}/i; const match = wikitext.match(chemboxRegex); return match ? match[0] : null; } function getFormulaFromWikitext(wikitext) { const chembox = getChemboxBlock(wikitext); if (!chembox) return null; const formulaMatch = chembox.match(/\|\s*Formula\s*=\s*([^|\n}]+)/i); if (formulaMatch) { let rawFormula = formulaMatch[1].replace(/<\/?sub>/gi, "").trim(); rawFormula = rawFormula.split(/\s+/)[0]; return rawFormula.split(',')[0].trim(); } const propRegex = /\{\{\s*Chembox[\s_]+Properties(?:[^{}]|\{\{(?:[^{}]|\{\{[^{}]*\}\})*\}\})*\}\}/i; const propSection = chembox.match(propRegex); if (propSection) { const content = propSection[0]; const allElements = ['Ac', 'Ag', 'Al', 'Am', 'Ar', 'As', 'At', 'Au', 'B', 'Ba', 'Be', 'Bh', 'Bi', 'Bk', 'Br', 'C', 'Ca', 'Cd', 'Ce', 'Cf', 'Cl', 'Cm', 'Cn', 'Co', 'Cr', 'Cs', 'Cu', 'D', 'Db', 'Ds', 'Dy', 'Er', 'Es', 'Eu', 'F', 'Fe', 'Fl', 'Fm', 'Fr', 'Ga', 'Gd', 'Ge', 'H', 'He', 'Hf', 'Hg', 'Ho', 'Hs', 'I', 'In', 'Ir', 'K', 'Kr', 'La', 'Li', 'Lr', 'Lu', 'Lv', 'Mc', 'Md', 'Mg', 'Mn', 'Mo', 'Mt', 'N', 'Na', 'Nb', 'Nd', 'Ne', 'Nh', 'Ni', 'No', 'Np', 'O', 'Og', 'Os', 'P', 'Pa', 'Pb', 'Pd', 'Pm', 'Po', 'Pr', 'Pt', 'Pu', 'Ra', 'Rb', 'Re', 'Rf', 'Rg', 'Rh', 'Rn', 'Ru', 'S', 'Sb', 'Sc', 'Se', 'Sg', 'Si', 'Sm', 'Sn', 'Sr', 'Ta', 'Tb', 'Tc', 'Te', 'Th', 'Ti', 'Tl', 'Tm', 'Ts', 'U', 'V', 'W', 'Xe', 'Y', 'Yb', 'Zn', 'Zr']; let data = {}; allElements.forEach(el => { const elRegex = new RegExp(`\\|\\s*${el}\\s*=\\s*(\\d*\\.?\\d+)`, 'i'); const elMatch = content.match(elRegex); if (elMatch && elMatch[1] !== "0") { data[el] = elMatch[1] === "1" ? "" : elMatch[1]; } }); const elementsPresent = Object.keys(data); if (elementsPresent.length > 0) { let formulaArray = []; const hasC = "C" in data; if (hasC) { formulaArray.push("C" + data["C"]); if ("H" in data) formulaArray.push("H" + data["H"]); } elementsPresent.filter(el => !(hasC && (el === "C" || el === "H"))).sort().forEach(el => { formulaArray.push(el + data[el]); }); return formulaArray.join(''); } } return null; } function getCASFromWikitext(wikitext) { const chembox = getChemboxBlock(wikitext); if (!chembox) return null; const idRegex = /\{\{\s*Chembox[\s_]+Identifiers(?:[^{}]|\{\{(?:[^{}]|\{\{[^{}]*\}\})*\}\})*\}\}/i; const idSection = chembox.match(idRegex); if (!idSection) return null; const content = idSection[0]; const nbsp = String.fromCharCode(160); const casMatch = content.match(/\|\s*CASNo\d*\b(?!\s*_)\s*=\s*([^|}\n]+)/i); if (casMatch) { let val = casMatch[1].replace(/\{\{[^}]+\}\}/g, "").replace(/\u00AD/g, "").split("&nbsp;").join(""); while (val.indexOf(nbsp) !== -1) val = val.replace(nbsp, ""); while (val.indexOf(" ") !== -1) val = val.replace(" ", ""); const cleanedCas = val.trim(); return /^\d{2,7}-\d{2}-\d$/.test(cleanedCas) ? cleanedCas : null; } return null; } async function getWikidataValue() { const qid = mw.config.get('wgWikidataItemId'); if (!qid) return null; const api = new mw.ForeignApi('https://www.wikidata.org/w/api.php'); const res = await api.get({ action: 'wbgetentities', ids: qid, props: 'claims', format: 'json', formatversion: 2 }); const claims = res.entities[qid].claims; const data = {}; if (claims.P274) data.formula = claims.P274[0].mainsnak.datavalue.value; if (claims.P231) data.cas = claims.P231[0].mainsnak.datavalue.value; return data; } async function startBackgroundCategoryScan() { const api = new mw.Api(); const titles = $('#mw-pages li a').map((i, el) => $(el).attr('title') || $(el).text()).get(); totalToScan = titles.length; if (totalToScan === 0) return; const chunks = arrayChunk(titles, 50); for (const chunk of chunks) { const res = await api.get({ action: 'query', prop: 'revisions', titles: chunk, rvprop: 'content', formatversion: 2 }); if (res.query && res.query.pages) { res.query.pages.forEach(page => { if (page.missing || !page.revisions) return; const wikitext = page.revisions[0].content; const f = getFormulaFromWikitext(wikitext); const c = getCASFromWikitext(wikitext); if (f || c) categoryDataCache[page.title] = { formula: f, cas: c }; }); } scanProgress += chunk.length; $('#caschemassist-cat-btn').text(`Scanning... ${scanProgress}/${totalToScan}`); } $('#caschemassist-cat-btn').text('Show missing CAS/Chem').prop('disabled', false); } async function renderCategoryAudit() { const api = new mw.Api(); const missingCheckTitles = []; Object.values(categoryDataCache).forEach(data => { if (data.formula) missingCheckTitles.push(data.formula); if (data.cas) missingCheckTitles.push(data.cas); }); if (missingCheckTitles.length === 0) { mw.notify("No valid Chembox data found in this category."); return; } const existenceMap = {}; const chunks = arrayChunk([...new Set(missingCheckTitles)], 50); for (const chunk of chunks) { const res = await api.get({ action: 'query', titles: chunk, formatversion: 2 }); if (res.query && res.query.pages) { res.query.pages.forEach(p => { existenceMap[p.title] = !p.missing; }); } } $('#mw-pages li').each(function() { const title = $(this).find('a').attr('title') || $(this).find('a').text().trim(); const data = categoryDataCache[title]; if (!data) return; if (data.formula && !existenceMap[data.formula]) { $(this).append($('<span>').css({ 'color': 'red', 'font-size': '0.85em', 'margin-left': '8px', 'font-weight': 'bold' }).text(` [${data.formula}]`)); } if (data.cas && !existenceMap[data.cas]) { $(this).append($('<span>').css({ 'color': 'darkred', 'font-size': '0.85em', 'margin-left': '8px', 'font-weight': 'bold' }).text(` [CAS: ${data.cas}]`)); } }); $('#caschemassist-cat-btn').text('Audit complete').prop('disabled', true); } async function handleSingleArticle() { const api = new mw.Api(); const currentTitle = mw.config.get("wgTitle"); const [wikiRes, wikidata] = await Promise.all([ api.get({ action: 'query', prop: 'revisions', titles: mw.config.get("wgPageName"), rvprop: 'content', formatversion: 2 }), getWikidataValue() ]); const page = wikiRes.query.pages[0]; if (!page || page.missing || !page.revisions) return; const wikitext = page.revisions[0].content; const formula = getFormulaFromWikitext(wikitext); const cas = getCASFromWikitext(wikitext); if (wikidata) { let mismatches = []; if (formula && wikidata.formula && formula !== wikidata.formula) { mismatches.push(`Formula mismatch: Chembox "${formula}" vs Wikidata "${wikidata.formula}"`); } if (cas && wikidata.cas && cas !== wikidata.cas) { mismatches.push(`CAS mismatch: Chembox "${cas}" vs Wikidata "${wikidata.cas}"`); } if (mismatches.length > 0) { const $warning = $('<div>').css({ 'background': '#fff2f2', 'border': '2px solid #d33', 'padding': '10px', 'margin-bottom': '1em', 'color': '#b32424' }).append($('<strong>').text('⚠️ Data Mismatch Detected: '), mismatches.join(' | ')); $('#mw-content-text').prepend($warning); } } async function checkAndRender(target, label, customWikitext) { const check = await api.get({ action: 'query', titles: target, formatversion: 2 }); if (check.query.pages[0].missing) { const $container = $('<div>').css({ 'background': '#f8f9fa', 'border': '1px solid #a2a9b1', 'padding': '10px', 'margin-bottom': '1em' }); const $btn = $('<button>').text(`Create redirect: ${target}`).click(async function() { await api.postWithEditToken({ action: 'edit', title: target, text: customWikitext, summary: `Creating redirect to [[${currentTitle}]] (${label})`, createonly: true }); mw.notify(`Created redirect: ${target}`); $container.fadeOut(400, function() { $(this).remove(); }); }); $container.append($('<strong>').text(`${label}: `), `Missing redirect. `, $btn); $('#mw-content-text').prepend($container); } } if (formula && formula !== currentTitle) { const formulaWikitext = `#REDIRECT [[${currentTitle}]]\n\n{{Redirect category shell|\n{{R from chemical formula}}\n}}`; await checkAndRender(formula, "Chemical formula", formulaWikitext); } if (cas && cas !== currentTitle) { const casWikitext = `#REDIRECT [[${currentTitle}]]\n\n{{Redirect category shell|\n{{R from CAS Registry Number}}\n{{R unprintworthy}}\n}}`; await checkAndRender(cas, "CAS number", casWikitext); } } function arrayChunk(arr, size) { const result = []; for (let i = 0; i < arr.length; i += size) { result.push(arr.slice(i, i + size)); } return result; } $(document).ready(async function() { const ns = mw.config.get("wgNamespaceNumber"); if (ns === 14) { if (await verifyTreeMembership()) { const $catContainer = $('#mw-pages'); if ($catContainer.length) { const $btn = $('<button>').text('Initializing scan...').attr('id', 'caschemassist-cat-btn').addClass('mw-ui-button').css({ 'margin': '0 10px 10px 0', 'float': 'right', 'position': 'relative', 'z-index': '100' }).prop('disabled', true).click(renderCategoryAudit); $catContainer.prepend($btn); startBackgroundCategoryScan(); } } } else if (ns === 0 && mw.config.get("wgAction") === "view") { handleSingleArticle(); } }); })(); //</nowiki> fvdmuvcp8lo9pv3ug2btz3g6wf5gi30 Talk:.gb 1 104686 739035 735287 2026-04-21T15:56:59Z MPostoronca-WMF 72719 testing 739035 wikitext text/x-wiki {{DYKtalk|2019年|6月1日}} this is an edit test edit {{ DYKEntry/archive | nominator = Rowingbohe | image = | question = [[英国]]因为使用[[.uk]]域名而'''[[.gb|废弃了哪一个]]'''[[互联网]][[国家代码顶级域名]]? | timestamp = 1558911236 | author = Rowingbohe | type = technology | article = .gb | hash = 05339082877c77c30c6dd066bba13d76260b0b02 | result = +|05339082877c77c30c6dd066bba13d76260b0b02|1559332225 | revid = 395647 | closets = 1559371219 }} **{{支持}}:符合标准。--[[User:Masdggg|<span style="color: RED;">'''風雲北洋'''</span>]]※[[User talk:Masdggg|Talk]] 2019年5月27日 (一) 13:12 (UTC) **{{支持}}:符合标准。[[User:Walter Grassroot|🌜山西特产批发零售™️🌽🌶️🍎🍠🐓🐐]]([[User talk:Walter Grassroot|留言]]) 2019年5月28日 (二) 05:46 (UTC) **{{支持}}:符合标准。--[[User:Unravel17|Unravel17]]([[User talk:Unravel17|留言]]) 2019年5月28日 (二) 07:15 (UTC) **{{支持}},符合标准。--[[Special:Contribs/Humbleblue|HB]] 2019年5月28日 (二) 11:12 (UTC) **{{支持}},符合标准。--[[U:SH6188 |<span style="font:100% Times;white-space:nowrap;border-radius:99em;padding:0 4em;box-shadow:2px 2px 11px #bbb;background:#EDA456;color:#9C0000 " lang="-en">KMB-ATENU139 </span>]] ([[UT:SH6188|討論]]) 2019年5月28日 (二) 12:18 (UTC) **{{支持}}:符合标准,很有趣的一个条目,说明国码域名和[[ISO 3166-1]]不等同。--[[User:dqwyy|dqwyy]] ([[User_talk:dqwyy|talk]]) <sub>落忆归海枫音乡</sub> 2019年5月29日 (三) 04:25 (UTC) **{{反對}}:正文不足400字,以參考資料充位元組,dyk標準原來降到這麼低--[[User:Doitagainagain|Doitagainagain]]([[User talk:Doitagainagain|留言]]) 2019年5月30日 (四) 18:28 (UTC) ***D17同学,想报复也找个合理点的理由好的吧,DYKC没有规定参考资料字数要减去,只规定字节数大于3000。请你提高知识水平再来评审。{{mute|Doitagainagain}}--<span style="font: 14px Comic Sans MS;text-shadow:0 1px 5px #66f9cf;">[[U:Rowingbohe|Rowing]][[UT:Rowingbohe|bohe♬~]]</span><small>欢迎关注近期[[WP:GAC|优良条目评选]] [[WP:TZ|Taichow]]/[[U:Rowingbohe/访客签名|Sign]]</small> 2019年5月30日 (四) 22:44 (UTC) ****那建議增至6000bytes再提優良--[[User:Doitagainagain|Doitagainagain]]([[User talk:Doitagainagain|留言]]) 2019年5月31日 (五) 09:44 (UTC) *****哈哈哈,优良还行。已阅。--<span style="font: 14px Comic Sans MS;text-shadow:0 1px 5px #66f9cf;">[[U:Rowingbohe|Rowing]][[UT:Rowingbohe|bohe♬~]]</span><small>欢迎关注近期[[WP:GAC|优良条目评选]] [[WP:TZ|Taichow]]/[[U:Rowingbohe/访客签名|Sign]]</small> 2019年5月31日 (五) 09:47 (UTC) ******還有,DYK也沒要求內容正確,那麼代表可以亂寫..--[[User:Doitagainagain|Doitagainagain]]([[User talk:Doitagainagain|留言]]) 2019年5月31日 (五) 09:49 (UTC) *******我用自己的沙盒查過,不計算Infobox和參考來源,正文只有1,626位元組,要是以前烏拉跨氪、街燈這些老前輩大抵會走出來反對。不過約定俗成的規則和正式規則並不是一回事,規則並未規定正文字數必須省略Infobox和參考來源,而且大家看不出問題,只能說大家的尺度寬鬆了。因此駁回。--[[U:春卷柯南|<font color="orange">春-{卷}-柯南</font>]]<font color="green">編輯數突破二萬</font> ( [[UT:春卷柯南|論]][[Special:Contribs/春卷柯南|功]]行[[Special:Diff/50396233|賞]]·[[U:春卷柯南/紀功石碑|刻石留名]] ) 2019年5月31日 (五) 09:56 (UTC) == foo == bar [https://duckduckgo.com] [[User:Dwalden test acctcreation3|Dwalden test acctcreation3]] ([[User talk:Dwalden test acctcreation3|talk]]) 13:05, 14 November 2025 (UTC) == foo == bar [[User:Dwalden test acctcreation3|Dwalden test acctcreation3]] ([[User talk:Dwalden test acctcreation3|talk]]) 13:07, 14 November 2025 (UTC) 1gkn7lcfv00b2ky97wdgn4r7wtzjg7t Wikipedia:Sandbox 4 107092 739020 737782 2026-04-21T14:56:49Z Axwvwxz 73360 My first bot edit for learning purposes 739020 wikitext text/x-wiki <noinclude>{{Sandbox}}</noinclude> == Please start your testing below this line == Hello from Termux! This edit was made by Axwvwxz using Pywikibot. s9b8899vk6qi5wb77hr835lp49om52a 739042 739020 2026-04-21T21:00:55Z Cewbot 33876 Clear the sandbox. If you want to keep it longer, please test it in [[Special:MyPage/Sandbox|personal sandbox]], you can also check the revision history of the sandbox. 739042 wikitext text/x-wiki <noinclude>{{Sandbox}}</noinclude> == Please start your testing below this line == 9v37rcaxoiwjar8n3q9n7dcsjdvcyin User:Nardog/sandbox2.js 2 118608 739068 738516 2026-04-22T03:41:26Z Nardog 40946 739068 javascript text/javascript (async function listTools() { let pageAction = mw.config.get('wgAction'); let isView = pageAction === 'view'; let isEdit = ['edit', 'submit'].includes(pageAction); if (!isView && !isEdit) return; let pageType = mw.config.get('wgCanonicalSpecialPageName') || mw.config.get('wgNamespaceNumber'); if (isView && !pageType && !mw.config.exists('wgRedirectedFrom') && !mw.config.get('wgIsRedirect') && !mw.config.get('wgPageName').includes('/') ) { return; } await mw.loader.using([ 'mediawiki.util', 'mediawiki.Title', 'mediawiki.api', 'mediawiki.interface.helpers.styles' ]); mw.loader.addStyleTag(`.listtools:not(#mw-content-subtitle .listtools) { font-size: 85%; } .listtools, .listtools a { font-weight: normal !important; font-style: normal; } .mw-datatable .listtools { display: block; } .listtools + .mw-whatlinkshere-tools, #watchlist-edit-form .listtools ~ .mw-changeslist-links, .mw-special-DisambiguationPageLinks .listtools + a { display: none; }`); let messages = Object.assign({ watched: 'Added "$1" to your watchlist', watchFail: `Couldn't watch "$1"`, unwatchFail: `Couldn't unwatch "$1"` }, window.listtoolsMessages); let getMsg = (key, ...args) => ( Object.hasOwn(messages, key) ? mw.format(messages[key], ...args) : key ); let notif; let watchHandler = async function (e) { e.preventDefault(); let $link = $(this); let $wrapper = $link.parent(); $link.detach(); let params = new URLSearchParams(this.search); let action = params.get('action'); $wrapper.text(getMsg(action + 'ing')); let pn = params.get('title').replaceAll('_', ' '); let promise = new mw.Api()[action](pn); if (notif) { notif.close(); notif = null; } try { let result = await promise; if (!result || !result[action + 'ed']) throw ''; let newAction = action === 'watch' ? 'unwatch' : 'watch'; params.set('action', newAction); $link.add(`.listtools-watch > a[href="${this.pathname + this.search}"]`) .attr('href', this.pathname + '?' + params) .text(getMsg(newAction)); if (action !== 'watch') return; let require = await mw.loader.using([ 'mediawiki.notification', 'mediawiki.watchstar.widgets' ]); notif = await mw.notify( new (require('mediawiki.watchstar.widgets'))('watch', pn, null, $.noop, { message: getMsg('watched', pn) }).$element, { tag: 'listtools' } ); } catch { notif = await mw.notify(getMsg(action + 'Fail', pn), { tag: 'listtools', type: 'error' }); } finally { $wrapper.html($link); } }; let extGetMain = function () { return this.title; }; let re = new RegExp(`(?:\\?title=|${ mw.util.escapeRegExp(mw.format(mw.config.get('wgArticlePath'), '')) })([^#&?]+)`); let processed = new WeakSet(); let processLinks = ($links, module, titles) => { let isBatch = !!titles; titles = titles || new Set(); $links.each(function (i) { if (processed.has(this)) return; let $link = $links.eq(i); let pn; if (module.useText) { pn = $link.text(); } else { let match = $link.attr('href')?.match(re); if (!match) return; pn = decodeURIComponent(match[1]); } let t = mw.Title.newFromText(pn); if (!t) return; if (module.titlesOnly) { let text = $link.text(); if (text !== pn.replaceAll('_', ' ') && (text !== t.getMainText() || t.namespace === 2) ) { return; } } if ($link.is('.external, .extiw')) { Object.assign(t, { getMain: extGetMain, host: this.host, namespace: 0, title: pn }); } else { if (t.namespace < 0) return; if ($link.hasClass('new')) { t.missing = true; } titles.add(t.getSubjectPage().toText()); } let $tools = $('<span>').addClass('listtools mw-changeslist-links') .data('listtools', t); tools.forEach(tool => { addTool($tools, tool); }); if ($link.is(':is(del, bdi) > :only-child')) { if (module.position === 'end') { $link.parent().parent().append(' ', $tools); } else { $link.parent().after(' ', $tools); } } else if (module.position === 'end') { $link.parent().append(' ', $tools); } else { $link.after(' ', $tools); } if (module.post) { module.post($tools); } processed.add(this); }); if (!isBatch) { getWatched(titles); } }; let tools = [ { name: 'edit', url: t => t.getUrl({ action: 'edit' }) }, { name: 'hist', url: t => !t.missing && t.getUrl({ action: 'history' }) }, { name: 'links', url: t => mw.util.getUrl('Special:WhatLinksHere/' + t) }, { name: 'watch', url: t => !t.host && t.getSubjectPage().getUrl({ action: 'watch' }), callback: watchHandler } ]; let addTool = ($tools, tool, escapedName) => { let t = $tools.data('listtools'); let $duplicate = escapedName && $tools.children('.listtools-' + escapedName); let url = tool.url; if (typeof url === 'function') { url = url(t); if (!url) { $duplicate?.remove(); return; } } let $link = $('<a>').attr('href', url).text(getMsg(tool.name)); if (t.host) { $link.prop('host', t.host); } if (tool.callback) { $link.on('click', tool.callback); } let $wrapper = $('<span>').addClass('listtools-' + tool.name) .append($link); let $next = tool.next && $tools.children('.listtools-' + tool.next); if ($next?.length) { $duplicate?.remove(); $next.before($wrapper); } else if ($duplicate?.length) { $duplicate.replaceWith($wrapper); } else { $tools.append($wrapper); } }; let extend = tool => { if (tool.label && !Object.hasOwn(messages, tool.label)) { messages[tool.name] = tool.label; } if (tool.next) { tool.next = $.escapeSelector(tool.next); } let existingTool = tools.find(t => t.name === tool.name); if (existingTool) { Object.assign(existingTool, tool); } else { tools.push(tool); } let escapedName = existingTool && $.escapeSelector(tool.name); let $allTools = $('.listtools'); $allTools.each(function (i) { addTool($allTools.eq(i), tool, escapedName); }); }; let getWatched = async titles => { if (!Array.isArray(titles)) { titles = [...titles].slice(0, 500); } if (!titles.length) return; (await new mw.Api().post({ action: 'query', titles: titles.slice(0, 50), prop: 'info', inprop: 'watched', formatversion: 2 }, { headers: { 'Promise-Non-Write-API-Action': 1 } })).query.pages.forEach(page => { if (!page.watched) return; $(`.listtools-watch > a[href="${mw.util.getUrl(page.title, { action: 'watch' })}"]`) .attr('href', mw.util.getUrl(page.title, { action: 'unwatch' })) .text(getMsg('unwatch')); }); getWatched(titles.slice(50)); }; mw.hook('listtools.ready').fire(extend); let catTreeCallback = (records, observer) => { let $links = $(records[0].target).find('.CategoryTreeItem > bdi > a'); if ($links.length) { observer.takeRecords(); observer.disconnect(); processLinks($links, catTreeModule); } }; let catTreeModule = { selector: '.CategoryTreeItem > bdi > a', types: [14, 'CategoryTree'], position: 'end', post: $tools => { $tools.parent().next('.CategoryTreeChildren').each(function () { new MutationObserver(catTreeCallback) .observe(this, { childList: true }); }); } }; let modules = [ { selector: '#mw-pages li > a, #mw-pages li > span > a', types: [14] }, catTreeModule, { selector: '#mw-imagepage-section-linkstoimage a, #mw-imagepage-section-globalusage a', types: [6] }, { selector: '#mw-globalusage-result a', types: ['GlobalUsage'] }, { selector: '.mw-search-result-heading > a, .searchalttitle > a.mw-redirect, .iw-result__title > a, .mw-search-exists a', types: ['Search'] }, { selector: '.mw-search-createlink a', types: ['Search'], titlesOnly: true }, { selector: '#watchlist-edit-form .cdx-table td > label > a', types: ['EditWatchlist'] }, { selector: '.plainlinks > li > a', types: ['AbuseLog'], titlesOnly: true }, { selector: '#mw-allmessagestable td:first-child > a:first-child:not(.new)', types: ['Allmessages'], position: 'end' }, { selector: '.mw-spcontent li a', types: ['DisambiguationPageLinks', 'Listredirects'], titlesOnly: true }, { selector: 'li > a:first-child', types: ['FileDuplicateSearch'] }, { selector: '.TablePager_col_title > a:first-child, .TablePager_col_template > a', types: ['LintErrors'], post: $tools => { $tools.parent().contents().slice(3).remove(); } }, { selector: 'form > ul > li > a', types: ['Nuke'], position: 'end', titlesOnly: true }, { selector: '.page-assessments a', types: ['PageAssessments'], titlesOnly: true }, { selector: '.TablePager_col_pr_page > a', types: ['Protectedpages'], position: 'end' }, { selector: '#mw-content-text > ul a', types: ['Protectedtitles'], position: 'end' }, { selector: '.mw-fr-pending-changes-page-title', types: ['PendingChanges'], post: $tools => { $tools.parent().contents().slice(3).remove(); } }, { selector: '#mw-content-text > ul a:first-child', types: ['StablePages'], position: 'end' }, { selector: '.TablePager_col__page a', types: ['TopicSubscriptions'] }, { selector: '.undeleteResult > a', types: ['Undelete'], position: 'end', useText: true }, { selector: '.TablePager_col_img_name > a:first-child', // types: ['Listfiles'], position: 'end' }, { selector: '.mw-newpages-pagename', post: $tools => { let $nodes = $tools.parent().contents(); $nodes.slice( $nodes.index($tools) + 1, $nodes.index($nodes.filter('.mw-newpages-length')) ).replaceWith(' '); } }, { selector: '#mw-whatlinkshere-list li > bdi > a' }, { selector: '.mw-changeslist-log-entry > a:not(.mw-changeslist-log-gblblock a, .mw-changeslist-log-globalauth a)', titlesOnly: true }, { selector: '.mw-logevent-loglines > li:not(.mw-logline-gblblock, .mw-logline-globalauth) > a', types: ['Log'], titlesOnly: true }, { selector: '#mw-diff-otitle1 > strong > a, #mw-diff-ntitle1 > strong > a', types: ['ComparePages'], position: 'end' }, { selector: '#movepage-oldlink, #movepage-newlink', types: ['Movepage'] }, { selector: '.mw-undelete-revision a:not(.mw-userlink, .mw-usertoollinks > a)', types: ['Undelete'], useText: true }, { selector: '.galleryfilename, ' + '.mw-allpages-chunk > li > a, ' + '.mw-prefixindex-list > li > a, ' + '.mw-changeslist-line.mw-changeslist-src-mw-categorize .mw-changeslist-line-inner > .comment > a, ' + '.mw-changeslist-line.mw-changeslist-src-mw-categorize .mw-changeslist-line-inner-comment > .comment > a, ' + '.mw-changeslist-line.mw-changeslist-src-mw-categorize .mw-enhanced-rc-nested > .comment > a' }, { selector: '.mw-spcontent li a', position: 'end', titlesOnly: true } ]; if (isEdit) { let post = $tools => { if (!$tools[0].closest('.templatesUsed')) return; $tools.parent().contents().last().each(function () { this.textContent = this.textContent.slice(1); }).end().slice(-3, -1).remove(); }; let callback = mw.util.debounce(() => { processLinks( $('.mw-editfooter-list a, #wikiPreview > .previewnote a'), { titlesOnly: true, post } ); }, 500); mw.hook('wikipage.editform').add($form => { callback(); $form.find('.templatesUsed').each(function () { if (processed.has(this)) return; processed.add(this); new MutationObserver(callback) .observe(this, { childList: true, subtree: true }); }); }); } else if (typeof pageType === 'number') { $(() => { processLinks($('.subpages a, .mw-redirectedfrom a, .redirectText a'), {}); }); } mw.hook('wikipage.content').add($content => { let titles = new Set(); let $links = $content.find('a'); modules.forEach(module => { if (module.types && !module.types.includes(pageType)) return; processLinks($links.filter(module.selector), module, titles); }); getWatched(titles); }); }()); mw.hook('listtools.ready').add(extend => { // extend({ // name: 'talk', // url: t => !t.isTalkPage() && t.canHaveTalkPage() && t.getTalkPage().getUrl(), // next: 'hist' // }); extend({ name: 'subject', url: t => t.isTalkPage() && t.getSubjectPage().getUrl(), next: 'hist' }); extend({ name: 'last', url: t => !t.missing && t.getUrl({ diff: 'cur', diffonly: 1 }), next: 'links' }); // extend({ // name: 'purge', // url: t => t.getUrl({ action: 'purge' }), // next: 'watch', // callback: function (e) { // e.preventDefault(); // let $link = $(this); // let $wrapper = $link.parent(); // $link.detach(); // $wrapper.text('purging'); // let pn = $wrapper.closest('.listtools').data('listtools').toText(); // new mw.Api().post({ // action: 'purge', // forcelinkupdate: 1, // titles: pn, // formatversion: 2 // }).then(response => { // if (response.purge[0].purged) { // mw.notify(`Purged "${pn}"'`); // } // }).always(() => { // $wrapper.html($link); // }); // } // }); extend({ name: 'copy', url: '#', callback: function (e) { e.preventDefault(); let text = $(this).closest('.listtools').data('listtools').toText(); let $input = $('<input>').attr({ type: 'text', readonly: '', style: 'position:fixed;top:-100%' }).val(text).appendTo(document.body); $input[0].select(); let copied; try { copied = document.execCommand('copy'); } catch (err) {} $input.remove(); if (copied) { mw.notify(`Copied "${text}"`); } else { mw.notify('Copy failed', { type: 'error' }); } } }); }); (mw.config.get('wgNamespaceNumber') || mw.config.get('wgAction') !== 'view') && mw.config.get('wgCanonicalSpecialPageName') !== 'GlobalContributions' && (function consecudiff() { mw.loader.addStyleTag('.consecudiff::before{content:" ["} .consecudiff::after{content:"]"} .consecudiff-top::before{content:" ⟨"} .consecudiff-top::after{content:"⟩"}'); let isHist = mw.config.get('wgAction') === 'history'; class Consecudiff { constructor(lis, isContribs) { this.isContribs = isContribs; this.isEnhanced = !isHist && !isContribs && lis[0].classList.contains('mw-enhanced-rc'); this.threshold = isContribs ? window.consecudiffContribsThreshold || 120 : isHist ? window.consecudiffHistThreshold || 720 : window.consecudiffThreshold || 720; this.strictMode = !isContribs && !!window.consecudiffDetectInterruptions; this.diffSelector = isHist ? 'a.mw-history-histlinks-previous' : '.mw-changeslist-diff'; this.permaSelector = this.isEnhanced && '.mw-enhanced-rc-time > a' || (isHist || isContribs) && 'a.mw-changeslist-date'; this.hybridSelector = this.diffSelector; if (this.permaSelector) { this.hybridSelector += ', ' + this.permaSelector; } this.topClass = isContribs ? 'mw-contributions-current' : 'mw-changeslist-last'; let dependencies = ['mediawiki.util']; if ((isHist || isContribs) && mw.config.get('wgUserLanguage') !== 'en') { dependencies.push('mediawiki.language.months'); } mw.loader.using(dependencies, () => { let chunks; if (isHist) { chunks = this.chunkByUser(lis); } else { chunks = []; this.groupByTitle(lis).forEach(group => { chunks.push(...this.chunkByUser(group)); }); } let subchunks = []; chunks.forEach(chunk => { subchunks.push(...this.divideByDate(chunk)); }); let linkPairs = []; subchunks.forEach(subchunk => { linkPairs.push(...this.makeLinks(subchunk)); }); linkPairs.forEach(([$span, parent]) => { $span.appendTo(parent); }); }); } groupByTitle(lis) { let selector = this.isContribs ? '.mw-contributions-title' : '.mw-changeslist-title'; let lisByTitle = {}; lis.forEach(li => { let link = (this.isEnhanced ? li.closest('table') : li) .querySelector(selector); if (!link) return; let title = link.textContent; if (!lisByTitle.hasOwnProperty(title)) { lisByTitle[title] = []; } lisByTitle[title].push(li); }); return Object.values(lisByTitle).filter(group => group.length > 1); } chunkByUser(lis) { if (this.isSingleContribs) { return [lis]; } let chunks = [], lastSplitAt = 0, prevUser; this.isSingleContribs = lis.some((li, i) => { let link = li.querySelector('.mw-userlink'); if (!link && this.isContribs) { return true; } let user = link && link.textContent; if (!link || i && user !== prevUser) { chunks.push(lis.slice(lastSplitAt, i)); lastSplitAt = i; } prevUser = user; }); if (this.isSingleContribs) { return [lis]; } chunks.push(lis.slice(lastSplitAt)); return chunks.filter(chunk => chunk.length > 1); } divideByDate(lis) { let chunks = [], lastSplitAt = 0, prevDate; lis.forEach((li, i) => { let date; if (isHist || this.isContribs) { date = this.parseDate( li.querySelector('.mw-changeslist-date').textContent ); } else { date = Date.parse( li.dataset.mwTs.replace(/(....)(..)(..)(..)(..)(..)/, '$1-$2-$3T$4:$5:$6Z') ); } if (date) { date = date / 60000; } if (i && prevDate - date > this.threshold) { chunks.push(lis.slice(lastSplitAt, i)); lastSplitAt = i; } prevDate = date; if (!this.strictMode || lastSplitAt === i) return; let prevDiff = lis[i - 1].querySelector(this.diffSelector); if (prevDiff) { let prevNext = mw.util.getParamValue('oldid', prevDiff.search); if (prevNext !== li.dataset.mwRevid) { chunks.push(lis.slice(lastSplitAt, i)); lastSplitAt = i; } } }); chunks.push(lis.slice(lastSplitAt)); return chunks.filter(chunk => chunk.length > 1); } makeLinks(lis) { let count = lis.length; let firstPerma; let start = lis.findIndex(li => ( firstPerma = li.querySelector(this.hybridSelector) )); if (start === -1 || count - start < 2) return []; let end, lastDiff; for (let i = count - 1; i > start; i--) { if (!isHist && !this.isContribs) { lastDiff = lis[i].querySelector(this.diffSelector); if (lastDiff || lis[i].classList.contains('mw-changeslist-src-mw-new') ) { end = i + 1; break; } } if (this.permaSelector && lis[i].querySelector(this.permaSelector)) { end = i + 1; break; } } if (!end) return []; count = end - start; let params = { diff: lis[start].dataset.mwRevid }; if (lastDiff) { params.oldid = mw.util.getParamValue('oldid', lastDiff.search); } else { params.oldid = lis[end - 1].dataset.mwRevid; if (isHist && lis[end - 1].querySelector(this.diffSelector) || this.isContribs && !lis[end - 1].querySelector('.newpage') ) { params.direction = 'prev'; } } let title = !isHist && mw.util.getParamValue('title', firstPerma.search); let url = mw.util.getUrl(title, params); let classes = 'consecudiff'; if (!isHist && lis[start].classList.contains(this.topClass)) { classes += ' consecudiff-top'; } return lis.slice(start, end).map((li, i) => [ $('<span>').addClass(classes).append( $('<a>') .attr('href', url) .text(this.convertNumber(count - i + '/' + count)) ), this.isEnhanced ? li.tagName === 'TR' ? li.lastElementChild : li.querySelector('.mw-changeslist-line-inner') : li ]); } parseDate(s) { let date = Date.parse(s); if (date) { return date; } if (s.includes(',')) date = Date.parse(s.replace(',', '')); if (date) { return date; } if (mw.loader.getState('mediawiki.language.months') !== 'ready') return; s = s.replace(/\D/g, c => { let n = mw.language.convertNumber(c, true); return Number.isNaN(n) ? c : n; }); let h, m; s = s.replace(/(\d\d?)[.:h](\d\d?)/, ($0, $1, $2) => { h = $1; m = $2; return ' '; }); if (!h) return; let y, dateFirst; s = s.replace(/^(.*?)(\d{4})(?!\d)/, ($0, $1, $2) => { y = $2; dateFirst = /\d/.test($1); return $1 + ' '; }); if (!y) return; let mo, d; if (dateFirst) { [d, s] = this.getDate(s); if (!d) return; [mo, s] = this.getMonth(s); if (mo === -1) return; } else { [mo, s] = this.getMonth(s); if (mo === -1) return; [d, s] = this.getDate(s); if (!d) return; } return new Date(y, mo, d, h, m).getTime(); } getMonth(s) { if (!this.months) { this.months = mw.language.months.abbrev .concat(mw.language.months.names, mw.language.months.genitive) .reverse(); } let mo = this.months.findIndex(mn => { let temp = s.replace(mn, ' '); if (temp !== s) { s = temp; return true; } }); if (mo === -1) { let [numeric, temp] = this.getDate(s); numeric = parseInt(numeric); if (numeric > 0 && numeric < 13) { mo = numeric - 1; s = temp; } } else { mo = 11 - mo % 12; } return [mo, s]; } getDate(s) { let d; s = s.replace(/(^|\D)(\d\d?)(?!\d)/, ($0, $1, $2) => { d = $2; return $1 + ' '; }); return [d, s]; } convertNumber(num) { try { return mw.language.convertNumber(num); } catch (e) { return num; } } } mw.hook('wikipage.content').add($content => { $content.find('.mw-pager-body').each(function () { let lis = this.querySelectorAll('.mw-contributions-list > li'); if (lis.length > 1) { new Consecudiff([...lis], !isHist); } }); if (isHist) return; let $lists = $content.filter('.mw-changeslist'); if (!$lists.length) { $lists = $content.find('.mw-changeslist'); } $lists.each(function () { let lis = this.querySelectorAll('.mw-changeslist-edit:not(.mw-changeslist-src-mw-categorize)[data-mw-revid]'); if (lis.length > 1) { new Consecudiff([...lis]); } }); }); }()); if (mw.config.get('wgNamespaceNumber') === 14 && ( mw.config.get('wgAction') === 'view' || !mw.config.get('wgArticleId') )) { mw.loader.load('//test.wikipedia.org/w/index.php?title=User:Nardog/sandbox8.js&action=raw&ctype=text/javascript'); mw.loader.using([ 'mediawiki.api', 'mediawiki.util', 'mediawiki.DateFormatter', 'oojs-ui-widgets', 'mediawiki.widgets', 'mediawiki.widgets.UserInputWidget', 'mediawiki.widgets.datetime', 'oojs-ui.styles.icons-interactions', 'oojs-ui.styles.icons-movement', 'mediawiki.interface.helpers.styles', 'user.options' ]); } $(function moveHistory() { if (!document.getElementById('p-tb')) return; mw.loader.using('mediawiki.util', () => { let clicked; mw.util.addPortletLink('p-tb', '#', 'Move history', 't-movehistory').firstElementChild.addEventListener('click', e => { e.preventDefault(); if (clicked) { if (window.moveHistoryDialog) { window.moveHistoryDialog.open(); } return; } clicked = true; mw.loader.load('//test.wikipedia.org/w/index.php?title=User:Nardog/sandbox5.js&action=raw&ctype=text/javascript'); mw.loader.using([ 'mediawiki.api', 'mediawiki.util', 'mediawiki.Title', 'mediawiki.DateFormatter', 'oojs-ui-windows', 'oojs-ui-widgets', 'mediawiki.widgets', 'mediawiki.widgets.DateInputWidget', 'oojs-ui.styles.icons-interactions', 'mediawiki.interface.helpers.styles' ]); }); }); }); $(function sectionSearch() { if (!document.getElementById('p-tb')) return; mw.loader.using('mediawiki.util', () => { let clicked; mw.util.addPortletLink('p-tb', '#', 'Section search', 't-sectionsearch').firstElementChild.addEventListener('click', e => { e.preventDefault(); if (clicked) { if (window.sectionSearchDialog) { window.sectionSearchDialog.open(); } return; } clicked = true; mw.loader.load('//test.wikipedia.org/w/index.php?title=User:Nardog/sandbox7.js&action=raw&ctype=text/javascript'); mw.loader.using([ 'mediawiki.api', 'mediawiki.util', 'oojs-ui-core', 'oojs-ui-windows', 'mediawiki.widgets', 'mediawiki.widgets.NamespacesMultiselectWidget' ]); }); }); }); mw.config.get('wgCanonicalSpecialPageName') === 'CentralAuth' && mw.loader.using('jquery.tablesorter', function sortCentralAuthByEditCount() { mw.hook('wikipage.content').add($content => { let $table = $content.find('.mw-centralauth-wikislist').has('td'); if (!$table.length) return; $table.tablesorter().data('tablesorter').sort([{ 4: 'desc' }, { 1: 'asc' }]); }); }); ['edit', 'submit'].includes(mw.config.get('wgAction')) && [10, 828].includes(mw.config.get('wgNamespaceNumber')) && !mw.config.get('wgTitle').endsWith('/doc') && mw.loader.load('//en.wikipedia.org/w/index.php?title=User:Nardog/AutoTestcases.js&action=raw&ctype=text/javascript', 's'); // ['edit', 'submit'].includes(mw.config.get('wgAction')) && // mw.loader.load('//en.wikipedia.org/w/index.php?title=User:Nardog/TemplatePreviewGuard.js&action=raw&ctype=text/javascript', 's'); // ['edit', 'submit'].includes(mw.config.get('wgAction')) && // $(function templatePreviewGuard() { // let button = document.querySelector('input[name="wpTemplateSandboxPreview"]'); // if (!button) return; // let proceed; // button.addEventListener('click', e => { // if (proceed) { // proceed = false; // return; // } // e.preventDefault(); // e.stopPropagation(); // let formData = new FormData(button.form); // let page = formData.get('wpTemplateSandboxPage'); // let temp = formData.get('wpTemplateSandboxTemplate'); // if (!page || !temp) return; // mw.loader.using('mediawiki.api').then(() => ( // new mw.Api().get({ // action: 'query', // titles: page, // prop: 'templates', // tltemplates: temp, // formatversion: 2 // }) // )).always(response => { // if (((((response || {}).query || {}).pages || [])[0] || {}).templates || // confirm(`"${page}" doesn't appear to transclude "${temp}". Continue?`) // ) { // proceed = true; // button.click(); // } // }); // }, true); // if (!mw.config.get('wgArticleId')) return; // let widgetEl = document.querySelector('#wpTemplateSandboxPage.oo-ui-widget'); // if (!widgetEl) return; // let pn = mw.config.get('wgPageName').replace(/_/g, ' '); // mw.loader.using(['mediawiki.api', 'oojs-ui-core']).then(() => ( // new mw.Api().get({ // action: 'query', // titles: pn, // prop: 'transcludedin', // tiprop: 'title', // tilimit: 'max', // formatversion: 2 // }) // )).then(response => { // if (!response.batchcomplete) return; // let pages = response.query.pages[0].transcludedin // .filter(o => o.title !== pn); // if (!pages.length) return; // let widget = OO.ui.infuse(widgetEl); // if (pages.length === 1) { // widget.setValue(pages[0].title); // return; // } // widget.$element.replaceWith( // new OO.ui.ComboBoxInputWidget({ // id: 'wpTemplateSandboxPage', // maxlength: widget.$input.prop('maxLength'), // name: widget.$input.prop('name'), // options: pages // .sort((a, b) => a.ns - b.ns || -(a.title < b.title)) // .map(o => ({ data: o.title })), // placeholder: widget.$input.prop('placeholder'), // tabIndex: widget.getTabIndex(), // value: widget.getValue() // }).on('enter', e => { // e.preventDefault(); // button.click(); // }).$element // ); // }); // }); ['edit', 'submit'].includes(mw.config.get('wgAction')) && mw.config.get('wgArticleId') && mw.config.get('wgPageContentModel') === 'wikitext' && $(async () => { let form = document.getElementById('editform'); if (!form) return; let formData = new FormData(form); let section = formData.get('wpSection'); if (section === 'new') return; let widget = document.getElementById('wpSummaryWidget'); if (!widget) return; let isOld = formData.get('altBaseRevId') > 0 || (formData.get('baseRevId') || formData.get('parentRevId')) !== formData.get('editRevId'); await mw.loader.using([ 'jquery.textSelection', 'mediawiki.util', 'mediawiki.api', 'oojs-ui-core', 'oojs-ui.styles.icons-editing-core' ]); let $textarea = $('#wpTextbox1'); let input = OO.ui.infuse(widget); let button = new OO.ui.ButtonWidget({ framed: false, icon: 'undo', classes: ['autosectionlink-button'], invisibleLabel: true, label: 'Restore previous section link' }).toggle().on('click', () => { let cache = button.getData(); input.setValue(input.getValue().replace( /^(\/\*.*?\*\/)?\s*/, cache[0] ? '/* ' + cache[0] + ' */ ' : '' )); updatePreview(cache[0]); cache.reverse(); }).on('toggle', () => { input.$input.css('width', `calc(100% - ${button.$element.width()}px)`); }); input.$input.after(button.$element); let update = mw.util.debounce($diff => { let lines = $textarea.textSelection('getContents').trimEnd().split('\n'); let firstLineNum; if (isOld) { let i, lastLineNum; $diff.find('td:last-child').each(function () { if (this.classList.contains('diff-lineno')) { i = this.textContent.replace(/\D+/g, '') - 1; } else if (this.classList.contains('diff-context')) { i++; } else if (this.classList.contains('diff-addedline')) { i++; if (!firstLineNum) { firstLineNum = i; } lastLineNum = i; } else if (this.classList.contains('diff-empty')) { if (!firstLineNum) { firstLineNum = i === 0 ? 1 : i; } lastLineNum = i; } }); lines.length = lastLineNum || 0; } else { let origLines = $textarea.prop('defaultValue').trimEnd().split('\n'); firstLineNum = lines.findIndex((line, i) => line !== origLines[i]) + 1; if (!firstLineNum) { firstLineNum = lines.length < origLines.length ? lines.length : 1; } for (let i = 1, x = lines.length, y = origLines.length; (section ? i < x : i <= x) && lines[x - i] === origLines[y - i]; i++ ) { lines.pop(); } } let re = /^(={1,6})\s*(.+?)\s*\1\s*(?:<!--.+-->\s*)?$/, lowest = 7; lines.slice(firstLineNum).forEach(line => { let match = line.match(re); if (match?.[1].length < lowest) { lowest = match[1].length; } }); let head; lines.slice(0, firstLineNum).reverse().some(line => { let match = line.match(re); if (match?.[1].length < lowest) { head = match[2]; return true; } }); if (head) { head = head .replace(/'''(.+?)'''|\[\[:?(?:[^|\]]+\|)?([^\]]+)\]\]|<\/?(?:abbr|b|bdi|bdo|big|cite|code|data|del|dfn|em|font|i|ins|kbd|mark|nowiki|q|rb|ref|rp|rt|rtc|ruby|s|samp|small|span|strike|strong|sub|sup|templatestyles|time|translate|tt|u|var)(?:\s[^>]*)?>|<!--.*?-->|\[(?:https?:)?\/\/[^\s\[\]]+\s([^\]]+)\]/gi, '$1$2$3') .replace(/''(.+?)''/g, '$1') .trim(); } else if (lines.length && section < 1 && lowest === 7) { head = ''; } let v = input.getValue(); let match = v.match(/^\/\*\s*(.+?)\s*\*\/\s*/); let prev = match?.[1]; if (prev === head) return; input.setValue(( head || head === '' ? '/* ' + head + ' */ ' : '' ) + (match ? v.slice(match[0].length) : v)); button.setData([prev, head]).toggle(true); updatePreview(head); }, 500); let updatePreview = head => { let $comment = $('.mw-summary-preview > .comment'); if (!$comment.length) return; let url; if (head) { url = mw.util.getUrl() + '#' + head.replace(/[\s_]+/g, '_'); } else if (head === '') { head = mw.messages.get('autocomment-top', '(top)'); url = mw.util.getUrl(); } let paren = [...mw.messages.get('parentheses', '($1)')][0]; let $nodes = $comment.contents(); let $ac = $nodes.eq(1); if ($nodes[0]?.textContent === paren && $ac.is('.autocomment:first-child')) { if (head) { $ac.children('a').attr('href', url).children('bdi').text(head); } else { if ($nodes[2]?.nodeType === 3) { $nodes[2].textContent = $nodes[2].textContent.trimStart(); } $ac.remove(); } } else if (head) { let rtl = document.body.classList.contains('sitedir-rtl'); $comment.prepend( paren, $('<span>').addClass('autocomment').append( $('<a>').attr({ href: url, title: mw.config.get('wgPageName').replaceAll('_', ' ') }).text(rtl ? '←' : '→').append( $('<bdi>').attr('dir', rtl ? 'rtl' : 'ltr').text(head) ), mw.messages.get('colon-separator', ': ') ) ); if ($nodes[0]?.nodeType === 3) { let text = $nodes[0].textContent; if (text.startsWith(paren)) { text = text.slice(paren.length); } $nodes[0].textContent = ' ' + text; } } }; if (isOld) { mw.hook('wikipage.diff').add(update); } else { $textarea.on('input', update); mw.hook('ext.CodeMirror.input').add(update); update(); } new mw.Api().loadMessagesIfMissing(['autocomment-top', 'colon-separator', 'parentheses']); mw.loader.addStyleTag('.autosectionlink-button{position:absolute;top:0;right:0;margin:0}'); }); (mw.config.get('wgNamespaceNumber') === -1 || mw.config.exists('wgDiffNewId') || mw.config.get('wgAction') === 'history') && (function copyRevId() { let handler = function (e) { e.preventDefault(); let text = this.closest('.diff td')?.querySelector('[data-mw-revid]')?.dataset.mwRevid || this.closest('[data-mw-revid]')?.dataset.mwRevid; if (!text) return; let $input = $('<input>').attr({ type: 'text', readonly: '', style: 'position:fixed;top:-100%' }).val(text).appendTo(document.body); $input[0].select(); document.execCommand('copy'); $input.remove(); let copied; try { copied = document.execCommand('copy'); } catch {} $input.remove(); if (copied) { mw.notify(`Copied "${text}"`); } else { mw.notify('Copy failed', { type: 'error' }); } }; mw.hook('wikipage.diff').add($diff => { $diff.find('#mw-diff-otitle1, #mw-diff-ntitle1').append( ' (', $('<a>').attr({ href: '#', role: 'button' }).on('click', handler).text('id'), ')' ); }); if (mw.config.get('wgAction') !== 'history') return; mw.hook('wikipage.content').add($content => { $content.find('.mw-pager-tools').append( $('<span>').append( $('<a>').attr({ href: '#', role: 'button' }).on('click', handler).text('id') ) ); }); }()); (mw.config.get('wgNamespaceNumber') === -1 || mw.config.exists('wgDiffNewId') || mw.config.get('wgAction') === 'history') && (() => { let handler = async function (e) { e.preventDefault(); let td = this.closest('.diff td'); let rev = td ? td.querySelector('[data-mw-revid]')?.dataset.mwRevid : this.closest('[data-mw-revid]')?.dataset.mwRevid; if (!rev) { mw.notify(`Couldn't get the revision.`, { tag: 'markasunseen', type: 'error' }); return; } let pn = td ? new URLSearchParams([...td.querySelectorAll('a')].pop()?.search).get('title') : mw.config.get('wgPageName'); if (!pn) return; await mw.loader.using('mediawiki.api'); let result = (await new mw.Api().postWithEditToken({ action: 'setnotificationtimestamp', [td ? 'newerthanrevid' : 'torevid']: rev, titles: pn, formatversion: 2 })).setnotificationtimestamp?.[0]; if (Object.hasOwn(result, 'notificationtimestamp')) { mw.notify(`Marked revisions ${td ? 'after' : 'since'} ${rev} as unseen.`, { tag: 'markasunseen', type: 'success' }); } else if (result?.notwatched) { mw.notify('This page is not on your watchlist.', { tag: 'markasunseen', type: 'warn' }); } else { mw.notify(`Couldn't mark revisions ${td ? 'after' : 'since'} ${rev} as unseen.`, { tag: 'markasunseen', type: 'error' }); } }; mw.hook('wikipage.diff').add($diff => { $diff.find('#mw-diff-otitle1').append( ' (', $('<a>').attr({ href: '#', role: 'button', title: 'Mark revisions after this one as unseen' }).on('click', handler).text('unseen'), ')' ); }); if (mw.config.get('wgAction') !== 'history') return; mw.hook('wikipage.content').add($content => { $content.find('.mw-pager-tools').append( $('<span>').append( $('<a>').attr({ href: '#', role: 'button', title: 'Mark revisions since this one as unseen' }).on('click', handler).text('unseen') ) ); }); })(); (mw.config.get('wgNamespaceNumber') === -1 || mw.config.exists('wgDiffNewId') || mw.config.get('wgAction') === 'history') && ((mw.config.get('wgNamespaceNumber') % 2 || mw.config.get('wgNamespaceNumber') === 4) || (mw.config.get('wgWikiID') === 'metawiki' && mw.config.get('wgPageContentModel') === 'wikitext')) && mw.loader.using(['mediawiki.util', 'mediawiki.Title'], function copyUnsig() { let handler = function (e) { e.preventDefault(); let parent = this.closest('li, td'); let ts = parent.textContent.match(/\d\d:\d\d, \d\d? [A-Z][a-z]+ \d{4}/)?.[0]; if (!ts) return; let user = parent.querySelector('.mw-userlink').textContent; if (mw.util.isIPv6Address(user)) { user = user.toUpperCase(); } let temp = mw.util.isIPAddress(user) ? 'unsigned IP' : 'unsigned'; let text = `{{subst:${temp}|${user}|${ts}}}`; let $input = $('<input>').attr({ type: 'text', readonly: '', style: 'position:fixed;top:-100%' }).val(text).appendTo(document.body); $input[0].select(); let copied; try { copied = document.execCommand('copy'); } catch {} $input.remove(); if (copied) { mw.notify(`Copied "${text}"`); } else { mw.notify('Copy failed', { type: 'error' }); } }; mw.hook('wikipage.diff').add($diff => { $diff.find('#mw-diff-otitle1, #mw-diff-ntitle1').filter(function () { if (mw.config.get('wgWikiID') === 'metawiki') { return true; } let link = this.querySelector('strong > a') || this.parentElement.querySelector('#differences-prevlink, #differences-nextlink'); if (!link) return; let t = mw.Title.newFromText(mw.util.getParamValue('title', link.search)); return t.isTalkPage() || t.namespace === 4; }).append( ' (', $('<a>').attr({ href: '#', role: 'button' }).on('click', handler).text('sig'), ')' ); }); if (mw.config.get('wgAction') !== 'history') return; mw.hook('wikipage.content').add($content => { $content.find('.mw-pager-tools').append( $('<span>').append( $('<a>').attr({ href: '#', role: 'button' }).on('click', handler).text('sig') ) ); }); }); // mw.config.get('wgAction') === 'history' && // mw.loader.using('mediawiki.util', function () { // mw.hook('wikipage.content').add($content => { // $content.find('a.mw-changeslist-date').after(function () { // return [ // ' (', // $('<a>').attr('href', mw.util.getUrl(null, { // action: 'edit', // oldid: this.closest('li').dataset.mwRevid // })).text('e'), // ')' // ]; // }); // }); // }); // ['Contributions', 'IPContributions', 'Blankpage'].includes(mw.config.get('wgCanonicalSpecialPageName')) && // mw.hook('wikipage.content').add($content => { // $content.find('.mw-changeslist-history').parent().after(function () { // return $('<span>').append( // $('<a>').attr( // 'href', // this.firstElementChild.getAttribute('href').slice(0, -7) + 'edit' // ).text('e') // ); // }); // }); if (screen.width < 500) { mw.loader.addStyleTag('@font-face{font-family:CharisW;src:url(//fontlibrary.org/assets/fonts/charis/10b9f94ed21e56254b068c91ead7ec6f/017b2b2ad86e09d3c22b8cf0dfc78247/CharisSILRegular.ttf) format(truetype)} @font-face{font-family:CharisW;font-weight:700;src:url(//fontlibrary.org/assets/fonts/charis/10b9f94ed21e56254b068c91ead7ec6f/6f5069ac6a300dad45383c952e92c573/CharisSILBold.ttf) format(truetype)} body .IPA{font-family:CharisW,sans-serif} .mw-highlight-lines > pre{width:120em}'); location.hash && $(() => { let target = document.querySelector(':target'); if (target?.getBoundingClientRect().top < 0) { target.scrollIntoView(); } }); } ['edit', 'submit'].includes(mw.config.get('wgAction')) && (mw.config.exists('wgCodeEditorCurrentLanguage') || mw.config.exists('cmMode') && mw.config.get('cmMode') !== 'mediawiki') && (function saveNEdit() { let notif; $(document.body).on('click', '#wpSave', async function (e) { if (e.ctrlKey || e.shiftKey || e.metaKey || e.altKey || e.originalEvent?.defaultPrevented ) { return; } e.preventDefault(); await mw.loader.using([ 'mediawiki.api', 'mediawiki.util', 'jquery.textSelection', 'oojs-ui-core' ]); let button = OO.ui.infuse(this.parentElement).setDisabled(true); let $textarea = $('#wpTextbox1'); let text = $textarea.textSelection('getContents'); let $summary = $('#wpSummary'); let formData = new FormData(this.form); let promise = new mw.Api().postWithEditToken({ action: 'edit', title: mw.config.get('wgPageName'), text: text, section: formData.get('wpSection') || undefined, summary: $summary.textSelection('getContents'), [$('#wpMinoredit').prop('checked') ? 'minor' : 'notminor']: 1, baserevid: formData.get('editRevId'), basetimestamp: formData.get('wpEdittime'), starttimestamp: formData.get('wpStarttime'), watchlist: $('#wpWatchthis').prop('checked') ? 'watch' : 'unwatch', watchlistexpiry: formData.get('wpWatchlistExpiry') || undefined, undo: formData.get('wpUndidRevision') || undefined, undoafter: formData.get('wpUndoAfter') || undefined, contentformat: formData.get('format'), contentmodel: formData.get('model'), assertuser: mw.config.get('wgUserName'), formatversion: 2 }); notif?.close(); notif = null; try { let response = await promise; if (response?.edit?.result !== 'Success') throw ''; $('#editform > input[name="wpUndidRevision"], #editform > input[name="wpUndoAfter"]').remove(); $textarea.data('origtext', text).prop('defaultValue', text); $summary.val($summary.prop('defaultValue')); if (mw.loader.getState('mediawiki.editRecovery.edit') === 'ready') { let storage = mw.loader.moduleRegistry['mediawiki.editRecovery.edit'].packageExports['storage.js']; storage.deleteData(mw.config.get('wgPageName')); storage.closeDatabase(); } notif = await mw.notify(response.edit.nochange ? 'No change' : [ document.createTextNode('Saved'), $('<p>').append( new OO.ui.ButtonWidget({ href: mw.util.getUrl(), target: '_blank', label: 'View' }).$element, new OO.ui.ButtonWidget({ href: mw.util.getUrl(null, { diff: response.edit.newrevid || 'cur', diffonly: 1 }), target: '_blank', label: 'Diff' }).$element, new OO.ui.ButtonWidget({ href: mw.util.getUrl(null, { action: 'history' }), target: '_blank', label: 'History' }).$element )[0] ], { tag: 'savenedit' }); } catch (error) { notif = await mw.notify(error?.error?.info || error || 'Save failed', { autoHideSeconds: 'long', tag: 'savenedit', type: 'error' }); } finally { button.setDisabled(); } }); }()); mw.config.get('wgNamespaceNumber') === 0 && mw.config.get('wgAction') === 'view' && mw.config.get('wgCategories')?.some(c => c.endsWith(' actors') || c.endsWith(' actresses')) && $(() => { let n = $.escapeSelector(mw.config.get('wgTitle').replace(/ \(.+\)$/, '')); let $links = $(`.hatnote a[title$="${n} filmography"], .hatnote a[title*="${n} on "], .hatnote a[title*="${n} performances"]`); if (!$links.length) return; let titles = {}; $links = $links.filter(function () { let text = this.textContent; return !(titles[text] = Object.hasOwn(titles, text)); }); mw.notify( $links.length === 1 ? $links.clone() : $('<ul>').append($links.clone().wrap('<li>').parent()), { autoHideSeconds: 'long' } ); }); ['Recentchanges', 'Recentchangeslinked', 'Watchlist'].includes(mw.config.get('wgCanonicalSpecialPageName')) && $.when($.ready, mw.loader.using([ 'user.options', 'mediawiki.util', 'mediawiki.api' ])).then(function rcMuter() { let os = mw.user.options.get('userjs-rcmuter'); let set = new Set(os && os.split('|')); let save = () => { let ns = [...set].join('|'); if (ns === mw.user.options.get('userjs-rcmuter')) return; new mw.Api().saveOption('userjs-rcmuter', ns); mw.user.options.set('userjs-rcmuter', ns); $edit.attr('data-rcmuter', set.size); }; mw.loader.addStyleTag('body:not(.rcmuter-disabled) .rcmuter-muted{display:none !important} .rcmuter-edit::after, .rcmuter-togglemuted::after{content:": " attr(data-rcmuter)}'); let $edit = $('<a>').attr({ class: 'rcmuter-edit', href: '#', 'data-rcmuter': set.size }).text('Edit muted').on('click', e => { e.preventDefault(); mw.loader.using([ 'oojs-ui-windows', 'mediawiki.widgets.UsersMultiselectWidget' ]).then(() => OO.ui.getWindowManager().getWindow('message')).then(dialog => { let multiselect = new mw.widgets.UsersMultiselectWidget({ $overlay: dialog.$overlay, ipAllowed: true, selected: [...set] }).connect(dialog, { change: 'updateSize', reorder: 'updateSize' }); let instance = dialog.open({ message: $([ document.createTextNode('Muted users:'), multiselect.$element[0] ]), size: 'medium' }); instance.opened.then(() => { setTimeout(() => { multiselect.focus().menu.toggle(false); }); }); instance.closed.then(result => { if (!result || result.action !== 'accept') return; set = new Set(multiselect.getSelectedUsernames()); save(); mw.notify('Changes will take effect in next load.', { tag: 'rcmuter' }); }); }); }); let buttonsShown; let $toggleButtons = $('<a>').attr('href', '#').text('Show toggle buttons').on('click', function (e) { e.preventDefault(); if (buttonsShown) { mw.hook('wikipage.content').remove(addButtons); $('.rcmuter-toggle').remove(); this.textContent = 'Show toggle buttons'; } else { mw.hook('wikipage.content').add(addButtons); this.textContent = 'Hide toggle buttons'; } buttonsShown = !buttonsShown; }); let $toggle = $('<a>').attr({ class: 'rcmuter-togglemuted', href: '#' }).text('Show muted').on('click', function (e) { e.preventDefault(); this.textContent = document.body.classList.toggle('rcmuter-disabled') ? 'Hide muted' : 'Show muted'; }); let $toggleSpan = $('<span>').hide().append($toggle); mw.util.addSubtitle( $('<span>').addClass('mw-changeslist-links').append( $('<span>').append($edit), $('<span>').append($toggleButtons), $toggleSpan )[0] ); let toggle = function (e) { e.preventDefault(); let user = $(this) .closest('.mw-userlink ~ .mw-usertoollinks, .mw-changeslist-line-inner-userLink ~ .mw-changeslist-line-inner-userTalkLink') .prevAll('.mw-userlink, .mw-changeslist-line-inner-userLink') .last().text().trim(); if (!user) { mw.notify(`Can't retrieve the username.`, { tag: 'rcmuter', type: 'error' }); return; } let muting = this.parentElement.classList.toggle('rcmuter-unmute'); set[muting ? 'add' : 'delete'](user); save(); this.textContent = muting ? 'unmute' : 'mute'; mw.notify(`${muting ? 'Muting' : 'Unmuting'} ${user} from next load.`, { tag: 'rcmuter' }); }; let addButtons = $content => { if (!$content.is('#mw-content-text, .mw-changeslist')) { $content = $('#mw-content-text'); if ($content.has('.rcmuter-toggle').length) return; } let $tools = $content.find('.mw-usertoollinks.mw-changeslist-links'); let $muted = $tools.filter('.rcmuter-muted *'); $tools.not($muted).append( $('<span>').addClass('rcmuter-toggle').append( $('<a>').attr('href', '#').text('mute').on('click', toggle) ) ); if (!$muted.length) return; $muted.append( $('<span>').addClass('rcmuter-toggle rcmuter-unmute').append( $('<a>').attr('href', '#').text('unmute').on('click', toggle) ) ); }; let mutedCount; let filter = function () { let muted = set.has(this.textContent); if (muted) mutedCount++; return muted; }; mw.hook('wikipage.content').add($content => { if (!$content.is('#mw-content-text, .mw-changeslist')) return; if (!set.size) { $toggleSpan.hide(); return; } mutedCount = 0; $content.find('.changedby > .mw-userlink:only-child') .filter(filter).closest('table').addClass('rcmuter-muted'); $content.find('.mw-userlink:not(.changedby > *, .comment *, .rcmuter-muted *)') .filter(filter).closest('.mw-changeslist-line, table').addClass('rcmuter-muted') .closest('table.mw-enhanced-rc').find('.changedby > .mw-userlink').filter(filter).addClass('rcmuter-muted'); $toggleSpan.toggle(!!mutedCount); $toggle.attr('data-rcmuter', mutedCount); }); }); location.hostname.endsWith('.wikipedia.org') && mw.config.get('wgNamespaceNumber') % 2 === 0 && // mw.config.get('wgArticleId') && mw.config.get('wgPageContentModel') === 'wikitext' && $.when($.ready, mw.loader.using('mediawiki.util')).then(function refRenamer() { if (!document.getElementById('p-tb')) return; let messages = Object.assign({ portlet: 'RefRenamer', loading: 'Loading RefRenamer...' }, window.refrenamerMessages); let clicked; mw.util.addPortletLink('p-tb', '#', messages.portlet, 't-refrenamer').firstElementChild.addEventListener('click', e => { e.preventDefault(); if (clicked) { if (window.refRenamer) { window.refRenamer(); } return; } clicked = true; mw.loader.load('//test.wikipedia.org/w/index.php?title=User:Nardog/sandbox6.js&action=raw&ctype=text/javascript'); mw.notify(messages.loading, { autoHideSeconds: 'long', tag: 'refrenamer' }); }); }); if (['edit', 'submit'].includes(mw.config.get('wgAction'))) { mw.loader.load('//en.wikipedia.org/w/index.php?title=User:Nardog/ExpandContractions.js&action=raw&ctype=text/javascript', 's'); mw.loader.load('//en.wikipedia.org/w/index.php?title=User:Nardog/Unpipe.js&action=raw&ctype=text/javascript', 's'); } mw.config.get('wgAction') !== 'history' && mw.loader.load('//en.wikipedia.org/w/index.php?title=User:Nardog/CopyCodeBlock.js&action=raw&ctype=text/javascript', 's'); mw.config.exists('wgDiffNewId') && mw.config.get('wgDiscussionToolsFeaturesEnabled') && (function () { let data = {}, clickHandler, autoClear, run; window.dtc = data; let highlight = revId => { let ids = data[revId]; if (!ids || !ids.length) return; mw.loader.moduleRegistry['ext.discussionTools.init'].packageExports['highlighter.js'] .highlightNewComments(mw.dt.pageThreads, true, ids); if (clickHandler) { $(document.body).off('click', clickHandler); return; } $._data(document.body, 'events').click.some(o => { if (String(o.handler).includes('highlighter.clearHighlightTargetComment(')) { $(document.body).off('click', o.handler); clickHandler = o.handler; return true; } }); $._data(window, 'events').popstate.some(o => { if (String(o.handler).includes('highlighter.highlightTargetComment(')) { $(window).off('popstate', o.handler); return true; } }); }; let scroll = revId => { let ids = data[revId]; if (!ids || !ids.length) return; let yToSpan = Object.fromEntries( ids.map(id => document.getElementById(id)).filter(Boolean) .map(span => [span.getBoundingClientRect().y, span]) ); let ys = Object.keys(yToSpan); if (!ys.length) return; let lower = ys.filter(y => y > 10); if (!lower.length || Math.max(...lower) < document.documentElement.clientHeight ) { yToSpan[Math.min(...ys)].scrollIntoView(); } else { yToSpan[Math.min(...lower)].scrollIntoView(); } }; let scrollToNext = function (e) { e.preventDefault(); let revId = mw.config.get('wgDiffOldId'); if (!revId || !data[revId]) return; let i = data[revId].indexOf( this.closest('[data-mw-thread-id]').dataset.mwThreadId ); if (i === -1) return; let next = data[revId][i + 1] || data[revId][0]; document.getElementById(next).scrollIntoView(); }; mw.hook('wikipage.content').add(async $content => { let revId = mw.config.get('wgDiffOldId'); if (!revId) return; let param = new URLSearchParams(location.search).get('diffonly'); if (param && param !== '0') return; if (data[revId]) { highlight(revId); return; } await mw.loader.using(['ext.discussionTools.init', 'mediawiki.util']); let begin = Date.parse($('#mw-diff-otitle1 .mw-diff-timestamp').data('timestamp')); data[revId] = mw.dt.pageThreads.getCommentItems() .filter(c => c.timestamp > begin).map(c => c.id); if (!data[revId].length) return; await new Promise(setTimeout); highlight(revId); $content.find('.ext-discussiontools-init-replylink-buttons').filter(function () { return data[revId].includes(this.dataset.mwThreadId); }).children('span:last-of-type').before( ' | ', $('<a>').attr({ href: '#', role: 'button' }).text('next').on('click', scrollToNext) ); if (run || !document.getElementById('p-tb')) return; run = true; let portlet = mw.util.addPortletLink('p-tb', '#', 'Scroll to next', 't-scrolltonext'); portlet.firstElementChild.addEventListener('click', e => { e.preventDefault(); scroll(mw.config.get('wgDiffOldId')); }); mw.util.addPortletLink('p-tb', '#', 'Toggle highlight', 't-togglehighlight').firstElementChild.addEventListener('click', e => { e.preventDefault(); autoClear = !autoClear; if (autoClear) { $(document.body).on('click', clickHandler)[0].click(); } else { highlight(mw.config.get('wgDiffOldId')); } }); mw.loader.addStyleTag(`#t-scrolltonext{position:fixed;bottom:${portlet.clientHeight}px} #t-togglehighlight{position:fixed;bottom:0}`); }); }()); mw.config.get('wgNamespaceNumber') === 6 && mw.config.get('wgAction') === 'view' && mw.hook('wikipage.content').add($content => { $content.find('.filehistory .mw-usertoollinks-contribs').after(function () { return [ ' | ', $('<a>').attr('href', `${ mw.config.get('wgScript') }?title=Special:ListFiles/${ this.pathname.replace(/^.+\//, '') }&ilshowall=1`).text('uploads') ]; }); }); ['edit', 'submit'].includes(mw.config.get('wgAction')) && mw.config.get('wgArticleId') && mw.config.get('wgPageContentModel') === 'wikitext' && $(function () { if (!$('input[name="wpSection"]').val()) return; mw.hook('wikipage.content').add(async $content => { let $refs = $content.find('.mw-ext-cite-warning-sectionpreview_no_text'); if (!$refs.length) return; let ids = {}; $refs.each(function () { ids[this.closest('[id]').id.replace(/-\d+$/, '')] = this; }); let response = await $.get(`/api/rest_v1/page/html/${encodeURIComponent(mw.config.get('wgPageName'))}`); $($.parseHTML(response)).find('.mw-reference-text').each(function () { ids[this.id.replace(/^mw-reference-text-|-\d+$/g, '')]?.replaceWith(this); }); }); }); mw.hook('moremenu.ready').add(config => { $('#mm-page-purge-cache > a').on('click', e => { e.preventDefault(); new mw.Api().post({ action: 'purge', forcelinkupdate: 1, titles: config.page.name, formatversion: 2 }).then(() => { location.href = mw.util.getUrl(); }); }); $('#mm-page-search-search-history-wikiblame > a').on('click', function (e) { e.preventDefault(); let q = prompt(); if (q === null) return; let href = this.href; if (q) { let removal = q[0] === '!'; if (removal) { q = q.slice(1); } href += '&needle=' + encodeURIComponent(q); if (removal) { href += '&binary_search_inverse=on'; } href += '&force_wikitags=on'; } open(href, '_blank'); }); $('#mm-page-expand-templates > a').on('click auxclick', function (e) { if (e.which > 2) return; e.preventDefault(); let revId = mw.config.get('wgRevisionId') || Number($('input[name=oldid]').val()); let url = revId ? '/w/rest.php/v1/revision/' + revId : '/w/rest.php/v1/page/' + config.page.encodedName; $.get(url).then(response => { $('<form>').attr({ method: 'post', action: this.href, target: '_blank' }).append( [ ['wpInput', response.source], ['wpContextTitle', config.page.name], ['wpRemoveComments', 1] ].map(([n, v]) => $('<input>').attr({ name: n, type: 'hidden' }).val(v)) ).appendTo(document.body).trigger('submit').remove(); }); }); }); mw.config.get('wgCanonicalSpecialPageName') === 'ApiSandbox' && mw.hook('apisandbox.formatRequest').add((...args) => { args[4].complete = function () { setTimeout(() => { mw.hook('wikipage.content').fire($('.oo-ui-pageLayout-active')); }, 100); }; }); ['edit', 'submit'].includes(mw.config.get('wgAction')) && mw.config.get('wgArticleId') && mw.config.get('wgPageContentModel') === 'wikitext' && $.when($.ready, mw.loader.using('mediawiki.storage')).then(async () => { let infuseAndCall = (query, method, ...args) => { let $widget = $(query); if ($widget.length) { return OO.ui.infuse($widget)[method](...args); } }; let section = $('input[name="wpSection"]').val(); if (section) { let $textarea = $('#wpTextbox1'); let source = $textarea.prop('defaultValue'); let save = () => { let newSource = $textarea.textSelection('getContents'); if (newSource === source) { mw.storage.session.remove('editfullpage'); } else { mw.storage.session.setObject('editfullpage', [ mw.config.get('wgPageName'), section, newSource.trimEnd(), infuseAndCall('#wpSummaryWidget', 'getValue') || '', Number(infuseAndCall('#wpMinoreditWidget', 'isSelected')) || 0, Number(infuseAndCall('#wpWatchthisWidget', 'isSelected')) || 0, infuseAndCall('#wpWatchlistExpiryWidget', 'getValue') || 'infinite' ]); } }; await mw.loader.using(['jquery.textSelection', 'oojs-ui-core']); setInterval(() => { mw.requestIdleCallback(save); }, 3000); window.addEventListener('beforeunload', save); return; } let data = mw.storage.session.getObject('editfullpage'); mw.storage.session.remove('editfullpage'); console.log(data); if (!data || data[0] !== mw.config.get('wgPageName')) return; let isNew = data[1] === 'new'; let isLead = data[1] === '0'; let $textarea = $('#wpTextbox1'); let source = $textarea.prop('defaultValue'); let newSource, start, msg, notifOpts = { autoHideSeconds: 'long' }; let orig = []; if (isNew) { await mw.loader.using(['jquery.textSelection', 'oojs-ui-core']); newSource = source + (data[3] ? '\n== ' + data[3] + ' ==\n\n' : '\n') + data[2] + '\n'; start = source.length; } else { await mw.loader.using(['jquery.textSelection', 'oojs-ui-core', 'mediawiki.api']); let { parse } = await new mw.Api().get({ action: 'parse', page: mw.config.get('wgPageName'), prop: 'sections', wrapoutputclass: '', disablelimitreport: 1, disableeditsection: 1, disabletoc: 1, formatversion: 2 }); let target = !isLead && parse.sections.find(s => s.index === data[1]); if (isLead || target) { let next = parse.sections.find(s => s.index - 1 === Number(data[1])); newSource = (isLead ? '' : [...source].slice(0, target.byteoffset)).join('') + data[2] + (next ? '\n\n' + [...source].slice(next.byteoffset).join('') : '\n'); start = isLead ? 0 : target.byteoffset; } else { newSource = source + '\n\n' + data[2] + '\n'; start = source.length; msg = `Section restored. Couldn't find the section. The source is appended at bottom.`; notifOpts.type = 'warn'; } orig[0] = infuseAndCall('#wpSummaryWidget', 'getValue'); infuseAndCall('#wpSummaryWidget', 'setValue', data[3]); } $textarea.textSelection('setContents', newSource); orig[1] = infuseAndCall('#wpMinoreditWidget', 'getSelected'); infuseAndCall('#wpMinoreditWidget', 'setSelected', data[4]); orig[2] = infuseAndCall('#wpWatchthisWidget', 'getSelected'); infuseAndCall('#wpWatchthisWidget', 'setSelected', data[5]); orig[3] = infuseAndCall('#wpWatchlistExpiryWidget', 'getValue'); infuseAndCall('#wpWatchlistExpiryWidget', 'setValue', data[6]); setTimeout(() => { $textarea.textSelection('setSelection', { start }); }); let notif = await mw.notify($([ document.createTextNode(msg || 'Section restored.'), $('<p>').append( new OO.ui.ButtonWidget({ flags: 'destructive', label: 'Discard' }).on('click', () => { $textarea.textSelection('setContents', source); if (orig[0]) { infuseAndCall('#wpSummaryWidget', 'setValue', orig[0]); } infuseAndCall('#wpMinoreditWidget', 'setSelected', orig[1]); infuseAndCall('#wpWatchthisWidget', 'setSelected', orig[2]); infuseAndCall('#wpWatchlistExpiryWidget', 'setValue', orig[3]); notif.close(); }).$element )[0] ]), notifOpts); }); mw.config.exists('wgPostEdit') && mw.loader.using('mediawiki.storage', () => { mw.storage.session.remove('editfullpage'); }); mw.config.get('wgAction') === 'history' && mw.hook('wikipage.content').add(async $content => { if (!$content.has('.mw-history-line-updated').length) return; let href = $content.find('a.mw-history-histlinks-current:not(.mw-history-line-updated a)').attr('href'); if (!href) { await mw.loader.using(['mediawiki.api', 'mediawiki.util']); let page = (await new mw.Api().get({ action: 'query', titles: mw.config.get('wgPageName'), prop: 'info', inprop: 'notificationtimestamp', formatversion: 2 })).query.pages[0]; let rev = (await new mw.Api().get({ action: 'query', titles: page.title, prop: 'revisions', rvprop: 'ids', rvlimit: 1, rvstart: Date.parse(page.notificationtimestamp) / 1000 - 1, formatversion: 2 })).query.pages[0].revisions?.[0].revid; if (!rev || rev >= page.lastrevid) return; href = mw.util.getUrl(page.title, { diff: page.lastrevid, oldid: rev }); } $content.find('.mw-history-compareselectedversions-button').first().after( ' ', $('<a>').attr({ class: 'unseendiff', href: href }).text('unseen') ); }); (async () => { let cspn = mw.config.get('wgCanonicalSpecialPageName'); let isBp = cspn === 'Blankpage'; if (!isBp && cspn !== 'Watchlist') return; await mw.loader.using('mediawiki.util'); let notify = async (text, options, pn) => { let msg = [document.createTextNode(text)]; if (pn) { msg.push( $('<p>').append( $('<a>').attr('href', mw.util.getUrl(pn)).text(pn), ' ', $('<span>').addClass('mw-changeslist-links').append( $('<span>').append( $('<a>') .attr('href', mw.util.getUrl(pn, { action: 'edit' })) .text('edit') ), $('<span>').append( $('<a>') .attr('href', mw.util.getUrl(pn, { action: 'history' })) .text('history') ) ) )[0] ); } if (isBp) { await $.ready; $('#mw-content-text').html(msg); } else { return mw.notify(msg, Object.assign(options || {}, { tag: 'unseendiff' })); } }; let getUrl = async pn => { await mw.loader.using('mediawiki.api'); let page = (await new mw.Api().get({ action: 'query', titles: pn, prop: 'info', inprop: 'notificationtimestamp', formatversion: 2 })).query.pages[0]; if (!page.notificationtimestamp) { notify(`Couldn't get the last seen time.`, { type: 'warn' }, pn); return; } let rev = (await new mw.Api().get({ action: 'query', titles: pn, prop: 'revisions', rvprop: 'ids', rvlimit: 1, rvstart: Date.parse(page.notificationtimestamp) / 1000 - 1, formatversion: 2 })).query.pages[0].revisions?.[0].revid; if (rev === page.lastrevid) { notify('Already seen.', { type: 'warn' }, pn); return; } if (!rev) { rev = (await new mw.Api().get({ action: 'query', titles: pn, prop: 'revisions', rvprop: 'ids', rvlimit: 1, rvstart: Date.parse(page.notificationtimestamp) / 1000 - 1, rvdir: 'newer', formatversion: 2 })).query.pages[0].revisions?.[0].revid; if (!rev) { notify(`Couldn't get the last seen revision.`, { type: 'warn' }, pn); return; } } if (rev > page.lastrevid) { notify(`Invalid rev for "${pn}" (rev: ${rev}, lastrevid: ${page.lastrevid})`, { autoHideSeconds: 'long', type: 'warn' }, pn); return; } return mw.util.getUrl(page.title, { diff: page.lastrevid, oldid: rev }); }; if (isBp) { let pn = mw.config.get('wgTitle').match(/^[^/]+\/unseendiff\/(.+)$/)?.[1]; if (!pn) return; notify('Loading...', null, pn); let href = await getUrl(pn); if (!href) return; notify('Redirecting...', null, pn); location.href = href; return; } let handler = async function (e) { if (e.which > 2) return; e.preventDefault(); let pn = this.dataset.pn; if (!pn) { notify(`Couldn't get the page name.`, { type: 'error' }); return; } let notifPromise = notify('Loading...', { autoHideSeconds: 'long' }); let href = await getUrl(pn); if (!href) return; $(`.unseendiff-loader[data-pn="${$.escapeSelector(pn)}"]`).attr({ class: 'unseendiff', href: href, target: '_blank' }).off('click auxclick', handler); if (e.type === 'auxclick' || e.ctrlKey || e.metaKey || e.shiftKey) { open(href); } else { this.click(); } (await notifPromise).close(); }; mw.hook('wikipage.content').add($content => { $content.find( '.mw-changeslist-src-mw-edit.mw-changeslist-watchedunseen:not(.mw-changeslist-watchedseen) .mw-changeslist-line-inner' ).each(function () { let pn = this.dataset.targetPage || this.closest('[data-target-page]')?.dataset.targetPage || this.closest('table.mw-enhanced-rc')?.querySelector('[data-target-page]')?.dataset.targetPage; if (!pn) return; $('<span>').append( $('<a>').attr({ class: 'unseendiff-loader', href: mw.util.getUrl(`Special:BlankPage/unseendiff/${pn}`), 'data-pn': pn }).on('click auxclick', handler).text('unseen') ).appendTo( [...this.querySelectorAll('.mw-pager-tools')].pop() || $('<span>').addClass('mw-changeslist-links mw-pager-tools').appendTo(this).before(' ') ); }); }); })(); ['Contributions', 'IPContributions', 'Blankpage'].includes(mw.config.get('wgCanonicalSpecialPageName')) && mw.loader.using('mediawiki.util', () => { let watched = new Set(); let query = async lis => { let titles = Object.keys(lis).slice(0, 50); if (!titles.length) return; await mw.loader.using('mediawiki.api'); let pages = (await new mw.Api().post({ action: 'query', titles: titles, prop: 'info', inprop: 'notificationtimestamp|watched', formatversion: 2 }, { headers: { 'Promise-Non-Write-API-Action': 1 } })).query.pages; for (let page of pages) { if (!Object.hasOwn(lis, page.title)) continue; if (page.watched) { watched.add(page); $(lis[page.title]).addClass('watched'); } if (!page.notificationtimestamp) continue; let rev = (await new mw.Api().get({ action: 'query', titles: page.title, prop: 'revisions', rvprop: 'ids', rvlimit: 1, rvstart: Date.parse(page.notificationtimestamp) / 1000 - 1, formatversion: 2 })).query.pages[0].revisions?.[0].revid; if (!rev || rev === page.lastrevid) continue; if (rev > page.lastrevid) { mw.notify($([ document.createTextNode('Invalid rev for "'), $('<a>').attr({ href: mw.util.getUrl(page.title, { action: 'history' }), target: '_blank' }).text(page.title)[0], document.createTextNode(`" (rev: ${rev}, lastrevid: ${page.lastrevid})`), ]), { autoHideSeconds: 'long', type: 'warn' }); continue; } $('<span>').append( $('<a>').attr({ class: 'unseendiff', href: mw.util.getUrl(page.title, { diff: page.lastrevid, oldid: rev }) }).text('unseen') ).appendTo( lis[page.title].map(li => ( [...li.querySelectorAll(':scope > .mw-pager-tools')].pop() || $('<span>').addClass('mw-changeslist-links mw-pager-tools').appendTo(li).before(' ') )) ); } titles.forEach(title => { delete lis[title]; }); query(lis); }; mw.hook('wikipage.content').add($content => { $content.find( '.mw-contributions-list > li:not(.mw-contributions-current)[data-mw-revid]' ).each(function () { let link = this.querySelector('a.mw-changeslist-date, a.mw-changeslist-history'); let pn = link ? new URLSearchParams(link.search).get('title') : ''; $('<span>').append( $('<a>').attr({ class: 'mw-changeslist-diff', href: mw.util.getUrl(pn, { diff: 'cur', oldid: this.dataset.mwRevid }) }).text('cur') ).appendTo( [...this.querySelectorAll(':scope > .mw-pager-tools')].pop() || $('<span>').addClass('mw-changeslist-links mw-pager-tools').appendTo(this).before(' ') ); }); if (mw.config.get('wgWikiID') === 'wikidatawiki') return; let lis = {}; $content.find('.mw-contributions-title').each(function () { let title = this.textContent; if (!Object.hasOwn(lis, title)) { lis[title] = []; } lis[title].push(this.closest('li')); }); Object.keys(lis).forEach(title => { if (watched.has(title)) { $(lis[title]).addClass('watched'); delete lis[title]; } }); query(lis); }); }); ['edit', 'submit'].includes(mw.config.get('wgAction')) && mw.loader.load('//test.wikipedia.org/w/index.php?title=User:Nardog/sandbox9.js&action=raw&ctype=text/javascript'); mw.config.get('wgWikiID') === 'metawiki' && (async () => { let css = mw.loader.addStyleTag(`.wishtitle { font-size: 90%; font-style: italic; word-break: break-word; } .wishtitle > a { color: var(--color-warning, #886425); } .wishtitle > a:visited { color: var(--border-color-warning--hover, #735421); } .wishtitle-declined > a { text-decoration: line-through; } .wishtitle-declined > a:hover, .wishtitle-declined > a:focus, .mw-underline-always .wishtitle-declined > a { text-decoration: line-through underline; } #watchlist-edit-form .wishtitle { display: inline-block; } .mw-search-result-heading > .wishtitle, .catchangesviewer-table .wishtitle { display: block; } .catchangesviewer-table:has(.wishtitle) { white-space: wrap; }`); let lang = mw.config.get('wgUserLanguage'); let titles; let loadTitles = async () => { await mw.loader.using('mediawiki.storage'); titles = titles || mw.storage.getObject('wishtitles'); if (titles?.lang !== lang) { titles = { lang, w: [], fa: [] }; } }; let updateTitles = async (crwstatuses, crwcontinue) => { await mw.loader.using('mediawiki.api'); let params = { action: 'query', list: 'communityrequests-wishes', crwlang: lang, crwstatuses: crwstatuses, crwprop: 'title|updated', crwsort: 'updated', crwdir: 'ascending', crwlimit: 'max', crwcontinue: crwcontinue, formatversion: 2 }; if (!crwcontinue && !crwstatuses && titles._) { params.crwcontinue = `|${titles._}|0`; } let response = await new mw.Api().get(params); let wishes = response?.query?.['communityrequests-wishes']; if (wishes?.length) { let $span = $('<span>'); wishes.forEach(w => { let id = w.crwtitle.match(/^Community Wishlist\/W(\d+)/)?.[1]; if (!id) return; titles.w[id - 1] = $span.html(w.title).text(); if (crwstatuses === 'declined') { (titles.wd = titles.wd || []).push(id - 1); } let faId = w.crfatitle?.match(/^Community Wishlist\/FA(\d+)/)?.[1]; if (!faId) return; titles.fa[faId - 1] = w.focusareatitle; }); if (!crwstatuses) { titles._ = wishes.at(-1).updated.replace(/\D/g, ''); } } let expiry = 86400; if (crwstatuses || crwcontinue) { let prev = mw.storage.getObject('_EXPIRY_wishtitles'); if (prev) { expiry = Math.round(Date.now() / 1000) + 86400 - prev; } } mw.storage.setObject('wishtitles', titles, expiry); crwcontinue = response?.continue?.crwcontinue; if (crwcontinue) { await updateTitles(crwstatuses, crwcontinue); } }; let getTitle = id => ( id[0] === 'W' ? titles.w[id.slice(1) - 1] : titles.fa[id.slice(2) - 1] ); let renderTitle = (title, id, tag = 'span') => { let classes = 'wishtitle'; if (id[0] === 'W' && titles.wd?.includes(id.slice(1) - 1)) { classes += ' wishtitle-declined'; } return $(`<${tag}>`).addClass(classes).append( $('<a>').attr({ href: `/wiki/Community_Wishlist/${id}`, title: `Community Wishlist/${id}` }).text(title) ); }; let callback = ([id, links]) => { let title = getTitle(id); if (!title) { return true; } $(links).after(' ', renderTitle(title, id)); }; let selector = '.mw-changeslist-title, ' + '.mw-changeslist-log-entry > a:not(.mw-userlink), ' + '.mw-changeslist-line.mw-changeslist-src-mw-categorize :is(.mw-changeslist-line-inner, .mw-changeslist-line-inner-comment, .mw-enhanced-rc-nested) > .comment > a, ' + '#watchlist-edit-form .cdx-table td > label > a, ' + '.mw-search-result-heading > a:not(:has(> .ext-communityrequests-entity-link--label)), ' + '.mw-contributions-title, ' + '#mw-whatlinkshere-list li > bdi > a, ' + '.mw-allpages-chunk > li > a, ' + '.mw-prefixindex-list > li > a, ' + '.mw-logevent-loglines > li > a, ' + '#mw-pages li > a, ' + '.catchangesviewer-table td:nth-child(3) > a'; mw.hook('wikipage.content').add(async $content => { let links = {}; $content.find('a').each(function () { if (!this.matches(selector)) return; let id = this.textContent.match( /^(?:Talk:|Translations:)?Community Wishlist\/((?:W|FA)\d+)/ )?.[1]; if (!id) return; (links[id] = links[id] || []).push(this); }); links = Object.entries(links); if (!links.length) return; await loadTitles(); links = links.filter(callback); if (!links.length) return; await updateTitles(); links = links.filter(callback); if (!links.length) return; await updateTitles('declined'); links.forEach(callback); }); let pn = mw.config.get('wgRelevantPageName'); let id = pn.match(/^(?:Talk:|Translations:)?Community_Wishlist\/((?:W|FA)\d+)/)?.[1]; if (!id) return; await $.ready; let extTitle = document.querySelector('.ext-communityrequests-wish--title'); if (extTitle && $('.mw-pt-languages-selected').attr('lang') === lang) return; await loadTitles(); let title = getTitle(id); if (!title) { await updateTitles(); title = getTitle(id); if (!title) { await updateTitles('declined'); title = getTitle(id); if (!title) return; } } let $title = renderTitle(title, id, 'div'); if (mw.config.get('skin') === 'vector-2022') { $title.prependTo('.vector-page-toolbar'); } else { $title.insertAfter('#firstHeading'); } css.textContent += ' .ext-communityrequests-entity-talk-header{display:none}'; if (extTitle) return; document.title = document.title.replace( pn.replaceAll('_', ' '), `${pn.replace(`Community_Wishlist/${id}`, title)} ($&)` ); })(); mw.config.get('wgWikiID') === 'metawiki' && mw.hook('wikipage.watchlistChange').add(async (isWatched, expiry) => { if (![0, 1].includes(mw.config.get('wgNamespaceNumber'))) return; let title = mw.config.get('wgTitle'); if (!/^Community Wishlist\/(?:W|FA)\d+$/.test(title)) return; if (isWatched) { await new mw.Api().watch(title + '/Votes', expiry); mw.notify('Watching /Votes too.'); } else { await new mw.Api().unwatch(title + '/Votes'); mw.notify('Unwatched /Votes too.'); } }); ['edit', 'submit'].includes(mw.config.get('wgAction')) && $(async () => { let $input = $('#wpTemplateSandboxTemplate'); if (!$input.length) return; mw.loader.addStyleTag('#templatesandbox-editform .oo-ui-fieldLayout{max-width:50em} #templatesandbox-editform .oo-ui-fieldLayout-field{flex-grow:999}'); let makeTemplateField = () => new OO.ui.FieldLayout( new mw.widgets.TitleInputWidget({ inputId: 'wpTemplateSandboxTemplate', name: 'wpTemplateSandboxTemplate', showMissing: false, value: $input.val() }), { label: 'Template name:' } ); if (mw.loader.getState('ext.TemplateSandbox') !== 'registered') { await mw.loader.using('mediawiki.widgets'); $input.parent().replaceWith(makeTemplateField().$element); return; } let require = await mw.loader.using([ 'ext.TemplateSandbox.TemplateSandboxTitleWidget', 'ext.TemplateSandbox.styles', 'jquery.makeCollapsible', 'user.options' ]); let widget = new (require('ext.TemplateSandbox.TemplateSandboxTitleWidget'))({ $overlay: true, id: 'wpTemplateSandboxPage', maxLength: 255, name: 'wpTemplateSandboxPage', placeholder: 'Page title', required: false, tabIndex: 10, templateTitleFunc: () => $('#wpTemplateSandboxTemplate').val() }); widget.$element.attr('data-ooui', '{"_":"mw.widgets.TemplateSandboxTitleWidget"}') .data('oouiInfused', widget); let fieldset = new OO.ui.FieldsetLayout({ classes: ['mw-templatesandbox-fieldset', 'mw-collapsed'], id: 'templatesandbox-editform', items: [ makeTemplateField(), new OO.ui.ActionFieldLayout( widget, new OO.ui.ButtonInputWidget({ id: 'wpTemplateSandboxPreview', name: 'wpTemplateSandboxPreview', label: 'Show preview', tabIndex: 10, type: 'submit', useInputTag: true }), { align: 'top' } ) ], label: 'Preview page with this template' }); fieldset.$label.append('&nbsp;', $('<span>').addClass('mw-collapsible-toggle-placeholder')); fieldset.$group.addClass('mw-collapsible-content'); $('#templatesandbox-editform').replaceWith(fieldset.$element.makeCollapsible()); let modules = ['ext.TemplateSandbox']; if (Number(mw.user.options.get('uselivepreview'))) { modules.push('ext.TemplateSandbox.preview'); } mw.loader.load(modules); }); mw.config.get('wgWikiID') === 'enwiki' && mw.config.get('wgCanonicalSpecialPageName') === 'Watchlist' && (async () => { mw.loader.addStyleTag('.xfdnotifier-sublinks::before{content:" ["} .xfdnotifier-sublinks::after{content:"]"} .xfdnotifier-sublinks > span:not(:first-child)::before{content:"\\2009·\\2009"} .mw-portlet.vector-menu[id^="p-xfdnotifier-"] a{display:inline}'); await mw.loader.using(['mediawiki.api', 'mediawiki.Title', 'mediawiki.storage']); let xfds = [ { id: 'rm', label: 'RM', full: 'Requested moves', cat: 'Requested moves', }, { id: 'rmt', label: 'RM/T', full: 'Requested moves (technical)', page: 'Wikipedia:Requested_moves/Technical_requests', titleExtractor: $page => ( $page.find(`[data-mw*='"wt":"RMassist/core"']`).closest('li').map(function () { return this.querySelector('a[rel="mw:WikiLink"]')?.title; }).get() ) }, { id: 'afd', label: 'AfD', full: 'Articles for deletion', cat: 'Articles for deletion' }, { id: 'mfd', label: 'MfD', full: 'Miscellaneous for deletion', cat: 'Miscellaneous pages for deletion' }, { id: 'tfd', label: 'TfD', full: 'Templates for deletion', cat: 'Templates for deletion' }, { id: 'tfm', label: 'TfM', full: 'Templates for merging', cat: 'Templates for merging' }, { id: 'cfd', label: 'CfD', full: 'Categories for deletion', cat: 'Categories for deletion' }, { id: 'cfr', label: 'CfR', full: 'Categories for renaming', cat: 'Categories for renaming' }, { id: 'cfsr', label: 'CfSR', full: 'Categories for speedy renaming', cat: 'Categories for speedy renaming' }, { id: 'cfm', label: 'CfM', full: 'Categories for merging', cat: 'Categories for merging' }, { id: 'cfs', label: 'CfS', full: 'Categories for splitting', cat: 'Categories for splitting' }, { id: 'cfl', label: 'CfL', full: 'Categories for listifying', cat: 'Categories for listifying' }, { id: 'cfc', label: 'CfC', full: 'Categories for conversion', cat: 'Categories for conversion' }, { id: 'cfgd', label: 'CfGD', full: 'Categories for general discussion', cat: 'Categories for general discussion' }, { id: 'ffd', label: 'FfD', full: 'Files for discussion', cat: 'Wikipedia files for discussion' }, { id: 'rfd', label: 'RfD', full: 'Redirects for discussion', cat: 'All redirects for discussion' }, { id: 'prod', label: 'PROD', full: 'Articles proposed for deletion', cat: 'All articles proposed for deletion' } ]; window.xfd = xfds; let queryTitles = async (xfd, titles) => { if (!titles.length) return; let response = await new mw.Api().get({ action: 'query', titles: titles.slice(0, 50), prop: 'info', inprop: 'watched', formatversion: 2 }); response?.query?.pages?.forEach(p => { if (p.watched) { xfd.pages.push(p.title); } }); await queryTitles(xfd, titles.slice(50)); }; let queryPage = async xfd => { let $page = $($.parseHTML(await $.get( `https://en.wikipedia.org/w/rest.php/v1/page/${encodeURIComponent(xfd.page)}/html` ))); await queryTitles(xfd, xfd.titleExtractor($page)); }; let queryCat = async (xfd, gcmcontinue) => { let response = await new mw.Api().get({ action: 'query', prop: 'info|categories', inprop: 'watched', clprop: 'sortkey', clcategories: `Category:${xfd.cat}`, generator: 'categorymembers', gcmtitle: `Category:${xfd.cat}`, gcmlimit: 'max', gcmsort: 'timestamp', gcmdir: 'older', gcmcontinue: gcmcontinue, formatversion: 2 }); response?.query?.pages?.forEach(p => { if (p.watched && p.categories?.[0]?.sortkeyprefix !== ' ') { xfd.pages.push(p.title); } }); if (response?.continue?.gcmcontinue) { await queryCat(xfd, response.continue.gcmcontinue); } }; let show = async (xfd, lastId, isCache) => { if (xfd.portlet && isCache) return; let portletId = 'p-xfdnotifier-' + xfd.id; if (xfd.portlet) { $(xfd.portlet).find('ul').empty(); if (!xfd.pages.length) return; } else { await $.ready; xfd.portlet = mw.util.addPortlet(portletId, xfd.label, '#' + lastId); } let $label = $(`#${portletId}-label`).attr('title', xfd.full); if (xfd.page) { $label.wrapInner($('<a>').attr('href', mw.util.getUrl(xfd.page))); } xfd.pages.forEach(p => { let t = mw.Title.newFromText(p); let isTalk = t.isTalkPage(); let $other = $('<a>').attr({ href: t[isTalk ? 'getSubjectPage' : 'getTalkPage']().getUrl(), title: isTalk ? 'subject' : 'talk' }).text(isTalk ? 's' : 't'); let link = mw.util.addPortletLink(portletId, t.getUrl(), p).querySelector('a'); $('<span>').addClass('xfdnotifier-sublinks').append( $('<span>').append($other), $('<span>').append( $('<a>').attr({ href: t.getUrl({ action: 'history' }), title: 'history' }).text('h') ) ).insertAfter(link); }); }; mw.hook('wikipage.content').add(mw.util.throttle(async () => { let cache = mw.storage.getObject('xfdnotifier') || {}; let lastId = 'p-tb'; for (let xfd of xfds) { let portletId = 'p-xfdnotifier-' + xfd.id; let now = Math.floor(Date.now() / 1000); if (now - cache[xfd.id]?.[0] < 600) { xfd.pages = cache[xfd.id].slice(1); await show(xfd, lastId, true); lastId = portletId; continue; } xfd.pages = []; if (xfd.cat) { await queryCat(xfd); } else if (xfd.page) { await queryPage(xfd); } cache[xfd.id] = [now, ...xfd.pages]; mw.storage.setObject('xfdnotifier', cache, 604800); await show(xfd, lastId); lastId = portletId; } }, 1800000)); })(); 8q2q2pdplaur6d3a47eb2hpnlykkqgz Talk:666 1 119269 739034 735325 2026-04-21T15:54:56Z MPostoronca-WMF 72719 739034 wikitext text/x-wiki this is an edit test == afsdf == {{slink|444|fsdaf}} [[User:Newslinger|Newslinger]] ([[User talk:Newslinger|talk]]) 02:23, 18 March 2021 (UTC) :Wow, you are talking here before that? [[User:Thingofme|Thingofme]] ([[User talk:Thingofme|talk]]) 10:42, 30 October 2021 (UTC) == test == test [[Special:Contributions/&#126;2026-18067-60|&#126;2026-18067-60]] ([[User talk:&#126;2026-18067-60|talk]]) 09:45, 26 March 2026 (UTC) s36ip15nlemkrnee1nh6v1fngxxlt7m User:SongVĩ.Bot II 2 124239 739037 738939 2026-04-21T17:00:14Z SongVĩ.Bot II 52414 [[User:SongVĩ.Bot II|Task 0]]: Đã 1576 ngày... 739037 wikitext text/x-wiki Cập nhật lần cuối: 22-04-2026 Đã 1576 ngày... r8rxsjhjjpmt041rv59ozvxgj5pdpkm MediaWiki:GrowthMentors.json 8 127601 739017 738001 2026-04-21T13:24:07Z Vincatest6 47176 /* growthexperiments-manage-mentors-summary-remove-self-with-reason:Vincatest6|testing mentorship reassignment */ 739017 json application/json { "Mentors": { "49911": { "message": null, "weight": 2, "username": "About672599" }, "44042": { "message": null, "weight": 2, "username": "Aseleste" }, "50263": { "message": "Testing", "weight": 0, "username": "DreZhsh" }, "30874": { "message": "Testing", "weight": 2, "username": "Elli" }, "27425": { "message": "Hello and welcome! I'll be happy to help you!", "weight": 0, "username": "Etonkovidova (WMF)" }, "51711": { "message": "Test", "weight": 2, "username": "GOnyeahialam (WMF)" }, "752": { "message": "I will be happy to explore together all these new features!", "weight": 1, "username": "Geraki" }, "1": { "message": "Sup?", "weight": 2, "username": "Jon Harald Søby" }, "39901": { "message": "Welcome to Wikipedia! I love editing about music, but you can ask me anything.", "weight": 2, "username": "MMiller (WMF)" }, "43912": { "message": "test222222222222222", "weight": 2, "username": "Martin Urbanec (WMF)" }, "43610": { "message": "Test", "weight": 4, "username": "Paloi Sciurala" }, "39808": { "message": "Testing", "weight": 2, "username": "Nemoralis" }, "50179": { "message": "Uh-huh?", "weight": 2, "username": "NguoiDungKhongDinhDanh" }, "48882": { "message": "Hi, Welcome to Wikipedia!", "weight": 2, "username": "OTichonova (WMF)" }, "34206": { "message": "Ask me about design stuff", "weight": 2, "username": "RHo (WMF)" }, "51965": { "message": "Test wew", "weight": 0, "username": "SGimeno (WMF)" }, "29210": { "message": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.啊啊啊", "weight": 1, "username": "Stang" }, "12061": { "message": "Blah blah blah", "weight": 2, "username": "Suffusion of Yellow" }, "50053": { "message": "Wikipedia:Requests/Help desk/Mentors to become a mentor. \u003Cimg src=1 onerror=\"alert()\"\u003E\u003C/img\u003E", "weight": 2, "username": "Sungodtemple" }, "21799": { "message": "test porpoise", "weight": 2, "username": "Tamzin" }, "51768": { "message": "Heh, hey!", "weight": 2, "username": "Vasmar1" }, "1639": { "message": null, "weight": 2, "username": "Wargo" }, "29926": { "message": "This experienced user knows you're new and can help you with editing.", "weight": 1, "username": "Zilant17" }, "52081": { "message": "testing the mentor features", "weight": 4, "username": "Zippybonzo" }, "48247": { "message": null, "weight": 0, "username": "Asartea" }, "40269": { "message": "test test test ", "weight": 2, "username": "KHarlan (WMF)" }, "51514": { "message": null, "weight": 0, "username": "Mentor dashboard usability test" }, "49608": { "message": null, "weight": 0, "username": "SixthGrave" }, "20771": { "message": null, "weight": 0, "username": "Tacsipacsi" }, "46860": { "message": null, "weight": 0, "username": "Valcio" }, "101": { "message": null, "weight": 0, "username": "Xaosflux" }, "21990": { "message": null, "weight": 0, "username": "Xiplus" }, "44996": { "message": "Yaaaay!", "weight": 2, "username": "Yahya" }, "28192": { "message": "test", "weight": 2, "username": "Abbe98" }, "29752": { "message": "Hello testers! ", "weight": 2, "username": "Trizek (WMF)" }, "16495": { "message": "Ffgg", "weight": 2, "username": "Iluvatar" }, "3312": { "message": "123", "weight": 2, "username": "Iniquity" }, "49609": { "message": "I will be happy to help!", "weight": 4, "username": "Neriah" }, "53741": { "message": "Hi", "weight": 2, "username": "Syunsyunminmin" }, "45556": { "message": "Hello, how can I help you today?", "weight": 2, "username": "Dyolf77 (WMF)" }, "51538": { "message": null, "weight": 2, "username": "Kylemaverick" }, "37377": { "message": "I am testing this feature 🙃", "weight": 2, "username": "Ата" }, "28876": { "message": "test", "weight": 2, "username": "Roan Kattouw (WMF)" }, "52574": { "message": "kjhjkh", "weight": 2, "username": "BMartinezCalvo (WMF)" }, "43722": { "message": null, "weight": 2, "username": "Ameisenigel" }, "54146": { "message": null, "weight": 2, "username": "Chqaz" }, "54035": { "message": "Hello testers, I'll be happy to help you!", "weight": 0, "username": "KStoller-WMF" }, "61446": { "message": "(just testing things, nevermind)", "weight": 0, "username": "MGrosse-WMF" }, "31153": { "message": "test", "weight": 2, "username": "Jack who built the house" }, "46247": { "message": "Hello! ", "weight": 2, "username": "Vincatest9" }, "19016": { "message": "Test wiki", "weight": 2, "username": "Jdlrobson" }, "50416": { "message": "Hello! I'm a test mentor. 123", "weight": 1, "username": "Zilant1b" }, "34459": { "message": null, "weight": 0, "username": "Jon Harald Søby (WMNO)" }, "53420": { "message": null, "weight": 0, "username": "JFernandez-WMF" }, "24817": { "message": "Test mentoring", "weight": 0, "username": "MusikAnimal" }, "60101": { "message": "Hi!", "weight": 4, "username": "Sunny Cryolite" }, "55545": { "message": "This experienced user knows you're new and can help you with editing.", "weight": 4, "username": "Martin Urbanec (public)" }, "29017": { "message": null, "weight": 2, "username": "Martin Urbanec" }, "61465": { "message": "Hi! I'm a WMF staff member and would like to help you with your contributions to Wikipedia!", "weight": 2, "username": "SPerry-WMF" }, "34390": { "message": "jhgnhg", "weight": 2, "username": "Samwalton9 (WMF)" }, "70274": { "message": null, "weight": 2, "username": "Vinca11sep01" }, "43668": { "message": "test", "weight": 2, "username": "Luky001" }, "71432": { "message": "mentor schmentor", "weight": 0, "username": "Dot.py" }, "72171": { "message": "Hello, and welcome! I'm SimpleObjects-9ei, and you can test stuff here. Have any questions? Just ask me.", "weight": 4, "username": "SimpleObjects-9ei" } } } n924nzfxd8iclhg4oq9bv3ivvf3g9cw Wikipedia:Village pump/topic list 4 146208 739069 739016 2026-04-22T05:41:17Z Cewbot 33876 [[User:Cewbot/log/20170915/configuration|Generate topic list: 6 topics]] 739069 wikitext text/x-wiki <!-- This page is auto-generated by bot. Please contact the bot operator to improve the tool. --> {| class="wikitable sortable mw-collapsible" style="float:left;" |- ! data-sort-type="number" style="font-weight: normal;" | <small>#</small> !! 💭 Title !! <span title="Count of comments">💬</span> !! <span title="Count of peoples in discussion">👥</span> !! 🙋 Last editor !! data-sort-type="isoDate" | <span title="Date/Time">🕒 <small>(UTC)</small></span> |- | style="text-align: right;" | 1 | [[Wikipedia:Village pump#Script|Script]] | style="text-align: right;" | 8 | style="text-align: right;" | 5 | style="background-color: #bbb;" | [[User:LuniZunie|LuniZunie]] | style="background-color: #bbb;" data-sort-type="isoDate" data-sort-value="2025-11-09T16:47:00.000Z" | 2025-11-09 <span style="color: blue;">16:47</span> |- | style="text-align: right;" | 2 | [[Wikipedia:Village pump#Report_concerning_Tanbiruzzammn|Report concerning Tanbiruzzammn]] | style="text-align: right;" | 2 | style="text-align: right;" | 2 | style="background-color: #bbb;" | [[User:Barras|Barras]] | style="background-color: #bbb;" data-sort-type="isoDate" data-sort-value="2025-12-09T21:45:00.000Z" | 2025-12-09 <span style="color: blue;">21:45</span> |- | style="text-align: right;" | 3 | [[Wikipedia:Village pump#Report_concerning_Bucheon|Report concerning Bucheon]] | style="text-align: right;background-color: #fcc;" | 1 | style="text-align: right;background-color: #fcc;" | 1 | style="background-color: #bbb;" | [[User:PieWriter|PieWriter]] | style="background-color: #bbb;" data-sort-type="isoDate" data-sort-value="2026-02-19T10:25:00.000Z" | 2026-02-19 <span style="color: blue;">10:25</span> |- | style="text-align: right;" | 4 | [[Wikipedia:Village pump#Versions_and_dates|Versions and dates]] | style="text-align: right;" | 2 | style="text-align: right;background-color: #fcc;" | 1 | style="background-color: #bbb;" | [[Special:Contributions/~2026-13668-13|<span style="color: #c20;">~2026-13668-13</span>]] | style="background-color: #bbb;" data-sort-type="isoDate" data-sort-value="2026-03-03T06:17:00.000Z" | 2026-03-03 <span style="color: blue;">06:17</span> |- | style="text-align: right;" | 5 | style="max-width: 24em" | <small>[[Wikipedia:Village pump#Upcoming_Wikimedia_Café_meetup_regarding_the_the_2026-2027_Wikimedia_Foundation_Annual_Plan|Upcoming Wikimedia Café meetup regarding the the 2026-2027 Wikimedia Foundation Annual Plan]]</small> | style="text-align: right;background-color: #fcc;" | 1 | style="text-align: right;background-color: #fcc;" | 1 | style="background-color: #ddd;" | [[User:Pine|Pine]] | style="background-color: #ddd;" data-sort-type="isoDate" data-sort-value="2026-03-30T03:46:00.000Z" | 2026-03-30 <span style="color: blue;">03:46</span> |- | style="text-align: right;" | 6 | [[Wikipedia:Village pump#Changes_to_electionadmin_userright|Changes to electionadmin userright]] | style="text-align: right;" | 3 | style="text-align: right;" | 3 | [[User:Robertsky|Robertsky]] | data-sort-type="isoDate" data-sort-value="2026-04-21T05:40:00.000Z" | 2026-04-21 <span style="color: blue;">05:40</span> |} {| class="wikitable mw-collapsible mw-collapsed" style="float: left; margin-left: .5em;;{{#if:{{{no_time_legend|}}}|display:none;|}}" ! title="From the latest bot edit" | Legend |- | style="background-color: #efe;" | * In the last hour |- | style="background-color: #eef;" | * In the last day |- | | * In the last week |- | style="background-color: #ddd;" | * In the last month |- | style="background-color: #bbb;" | * More than one month |- ! Manual settings |- | style="max-width: 12em;" | <small>When exceptions occur,<br />please check [[User:Cewbot/log/20170915/configuration|the setting]] first.</small> |- |} {{Clear}} kq36onm99hy32echx7xzln9cna437wy Vorlage:Coordinate 0 148889 739052 559543 2026-04-22T00:03:43Z InternetArchiveBot 34092 Rescuing 1 sources and tagging 0 as dead.) #IABot (v2.0.9.5 739052 wikitext text/x-wiki {{Infobox Gemeinde in Deutschland |Art = Stadt |Wappen = Reinbek Wappen.svg |Breitengrad = 53.510211 |Längengrad = 10.250318 |Lageplan = Reinbek in OD.svg |Bundesland = Schleswig-Holstein |Kreis = Stormarn |Höhe = 27 |PLZ = 21465 |Vorwahl = 040, 04104 |Gemeindeschlüssel = 01062060 |LOCODE = DE REI |Gliederung = [[Liste der Bezirke und Stadtteile Reinbeks|6 statistische Bezirke und 22 Stadtteile]] |Straße = Hamburger Straße 5–7 |Website = [https://www.reinbek.de/ www.reinbek.de] |Bürgermeister = [[Björn Warmer]] |Partei = SPD }} '''Reinbek''' ([[Niederdeutsche Sprache|niederdeutsch]] ''Reinbeek''), in der südlichen [[Geest]] [[Schleswig-Holstein]]s gelegen, ist mit etwa 28.000 Einwohnern die zweitgrößte Stadt im [[Kreis Stormarn]]. Die [[Mittelstadt]] liegt im östlichen Ballungsraum [[Hamburg]]s und gehört zur [[Metropolregion Hamburg]]. == Geografie == Die Ost- und Südgrenze Reinbeks bildet die zum ''Mühlenteich'' aufgestaute, naturgeschützte [[Bille]]. Die zwischen den Ortsteilen liegenden Flächen werden zum Teil noch landwirtschaftlich genutzt. Geprägt vom angrenzenden [[Sachsenwald]], bietet Reinbek ein grünes, erholsames Stadtbild. Ein Großteil der Stadt ist mit Einzelhäusern bebaut, das Gebiet rings um den Täby-Platz und das Paul Luckow-Stadion besteht zum großen Teil aus mehrstöckigen Mietshäusern, die im Stil der 1960er Jahre erbaut wurden. Das höchste von ihnen, das Sachsenwald-Hochhaus mit 20 Stockwerken, befindet sich in der Hamburger Straße. Zu Reinbek gehören die Stadtteile ''Alt-Reinbek'', [[Hinschendorf]], [[Schönningstedt]], [[Neuschönningstedt]], [[Ohe (Reinbek)|Ohe]] mit [[Büchsenschinken]] und das jüngere Neubaugebiet [[Krabbenkamp]] (→[[Liste der Bezirke und Stadtteile Reinbeks]]). Direkt angrenzend liegen die Hamburger Stadtteile [[Hamburg-Bergedorf|Bergedorf]] und [[Hamburg-Lohbrügge|Lohbrügge]]. == Geschichte == {{Hauptartikel|Geschichte der Stadt Reinbek}} Von der Besiedlung des heutigen Reinbeker Gebietes in bereits vorgeschichtlicher Zeit zeugen zahlreiche [[Hügelgrab|Hügelgräber]]. Die erste urkundlich überlieferte Erwähnung Reinbeks datiert allerdings erst auf das Jahr 1238 und geht auf die Gründung des gleichnamigen [[Zisterzienserinnen]]klosters (siehe [[Kloster Reinbek]]) zurück. Die ältesten bekannten Schreibformen des Ortsnamens sind ''(ville) Reinebec'' (1238), ''(in) Reynebeke'' (1309 und 1350), ''(to deme) Reynenbeke'' (1400) und ''(tome) Rynenbeke'' (1466); der Name wird als Kompositum aus dem Grundwort ''bek'' für „Bach“ und dem Adjektiv „rein“ als Bestimmungswort gedeutet.<ref>[[Wolfgang Laur]]: ''Historisches Ortsnamenlexikon von Schleswig-Holstein'', 2.&nbsp;Aufl., S.&nbsp;538.</ref> Nach der Zerstörung des Klosters (1534) gewann der Ort erst mit dem Bau der Schlossanlage (1572) wieder an Bedeutung. [[Datei:Mühlenteich und Reinbeker Schloss im Winter.jpg|mini|Der Mühlenteich und das Reinbeker Schloss im Winter]] Die Ansiedlung von Handwerkern im späten 18. Jahrhundert brachte endlich wirtschaftliches Wachstum. Einen entscheidenden Impuls für die Entwicklung des Ortes gab jedoch der Bau der Eisenbahnstrecke zwischen Hamburg und [[Berlin]] (1846): Reinbek wurde vorübergehend zum Kurort und beliebten Ausflugsziel. Die alte Schreibweise „Reinbeck“ wurde am 1. September 1877 durch eine Anordnung über die einheitliche Regelung der Schreibweise für Ortsnamen von der Provinzialregierung in Schleswig in „Reinbek“ geändert. Zum Ende des [[Zweiter Weltkrieg|Zweiten Weltkrieges]] wurde Deutschland schrittweise besetzt. Am 3. Mai 1945 besetzten britischen Truppen auch Reinbek, das benachbarte [[Glinde]] sowie den letzten Teil des noch unbesetzten [[Kreis Stormarn|Stormarns]].<ref>[[Hamburger Abendblatt]]: [http://www.abendblatt.de/region/stormarn/article205288543/Vor-siebzig-Jahren-kapitulierte-die-Stadt-Ahrensburg.html Kriegsende. Vor siebzig Jahren kapitulierte die Stadt Ahrensburg], vom: 2. Mai 2015; abgerufen am: 31. Mai 2017</ref> Des Weiteren begann am Nachmittag des Tages auch die Besetzung [[Hamburg]]s, die zuvor in der [[Villa Möllering]] bei [[Lüneburg]] vereinbart worden war. Einen Tag später unterschrieb zudem [[Hans-Georg von Friedeburg]] im Auftrag des letzten [[Reichspräsident]]en [[Karl Dönitz]], der sich zuvor mit der [[Regierung Dönitz|letzten Reichsregierung]] in den [[Sonderbereich Mürwik]] abgesetzt hatte, die [[Teilkapitulation der Wehrmacht für Nordwestdeutschland, Dänemark und die Niederlande]].<ref>[https://web.archive.org/web/20131104080252/http://www.volksbund.de/fileadmin/redaktion/BereichInfo/Textsammlungen/Ausstellungen/0400_ausstellung_timeloberg/Timeloberg.pdf Die Kapitulation auf dem Timeloberg] (PDF, 16. S.; 455&nbsp;kB)</ref> Die [[Bedingungslose Kapitulation der Wehrmacht]] folgte am 8. Mai 1945. Zum Kriegsende erlebte Reinbek einen verstärkten Zuzug von Flüchtlingen und durch Kriegseinwirkung obdachlos gewordenen Hamburgern. Seit den 1960er Jahren wurden mehrere Gewerbegebiete erschlossen und erweitert. Am 28. Juni 1952 erhielt Reinbek das [[Stadtrecht]]. Am 1. Januar 1974 wurden die Gemeinde [[Schönningstedt]] (mit [[Neuschönningstedt]] und [[Ohe (Reinbek)|Ohe]]) sowie ein Teil der Gemeinde Glinde mit damals etwa 100 Einwohnern und ein Teil der aufgelösten Gemeinde Stemwarde eingegliedert.<ref>{{Literatur | Herausgeber = Statistisches Bundesamt | Titel = Historisches Gemeindeverzeichnis für die Bundesrepublik Deutschland. Namens-, Grenz- und Schlüsselnummernänderungen bei Gemeinden, Kreisen und Regierungsbezirken vom 27. Mai 1970 bis 31. Dezember 1982 | Jahr = 1983 | Verlag = W. Kohlhammer GmbH | Ort = Stuttgart/Mainz | ISBN = 3-17-003263-1 | Seiten = 186}}</ref> Im Jahre 1978 kam das bisher landwirtschaftlich genutzte Gebiet Krabbenkamp, das vormals zu Schönningstedt gehörte, als weiterer Stadtteil hinzu. == Religion == Reinbek gehörte ursprünglich zum [[Kirchspiel]] [[Kirchsteinbek|Steinbek]], bis es 1894 zu einer eigenständigen [[Evangelisch-lutherische Kirchen|evangelisch-lutherischen]] [[Kirchengemeinde]] wurde. Die [[Neogotik|neogotische]] Kirche (heute Maria-Magdalenen-Kirche) wurde 1901 errichtet. 1908 gründete sich die [[Römisch-katholische Kirche|römisch-katholische]] Kirchengemeinde, die 1953 die Herz-Jesu-Kirche erbauen ließ. In Reinbek sind 44 % der Bevölkerung evangelisch und 9 % katholisch, 26 % gehören anderen Konfessionen an, 22 % sind ohne Religionszugehörigkeit. Die bedeutendsten Gemeinden der Stadt sind: * [[Ansgar von Bremen|Ansgar]]-Kirchengemeinde Schönningstedt-Ohe (evangelisch-lutherisch) * Kirchengemeinde [[Gethsemane]] Neuschönningstedt (evangelisch-lutherisch) * [[Maria-Magdalenen-Kirche (Reinbek)|Maria-Magdalenen-Kirche]] (evangelisch-lutherisch) * [[Nathan-Söderblom-Kirche (Reinbek)|Nathan-Söderblom-Kirche]] (evangelisch-lutherisch) * [[Herz-Jesu-Kirche (Reinbek)|Herz-Jesu]]-Gemeinde (römisch-katholisch) * [[Evangelisch-Freikirchliche Gemeinde]] ([[Baptisten]]) == Politik == === Stadtvertretung === Die letzten drei Kommunalwahlen [[Kommunalwahlen in Schleswig-Holstein 2018|am 6. Mai 2018]], [[Kommunalwahlen in Schleswig-Holstein 2013|am 26. Mai 2013]]<ref>{{Webarchiv|url=http://www.reinbek.de/wahlen/KW2013.html |wayback=20160304064515 |text=Archivierte Kopie}}</ref> und [[Kommunalwahlen in Schleswig-Holstein 2008|am 25. Mai 2008]]<ref>{{Cite web |title=Archived copy |url=http://www.reinbek.de/files/Wahlen/GKW_25052008.pdf#page=10 |access-date=2023-02-21 |archive-date=2016-03-04 |archive-url=https://web.archive.org/web/20160304074748/http://www.reinbek.de/files/Wahlen/GKW_25052008.pdf#page=10 }}</ref> führten zu folgenden Ergebnissen: {| class="wikitable" | colspan="2" | '''Parteien und Wählergemeinschaften''' | align="center" | '''%<br />2018''' | align="center" | '''Sitze<br />2018''' | align="center" | '''%<br />2013''' | align="center" | '''Sitze<br />2013''' | align="center" | '''%<br />2008''' | align="center" | '''Sitze<br />2008''' | rowspan="12" |{{Wahldiagramm | LAND = DE | TITEL = Kommunalwahl 2018 | JAHRALT = 2013 | JAHRNEU = 2018 | GUV = ja | PARTEI1 = CDU | ERGEBNIS1 = 27.5 | ERGEBNISALT1 = 30.7 | PARTEI3 = SPD | ERGEBNIS3 = 20.7 | ERGEBNISALT3 = 26.6 | PARTEI2 = GRÜNE | ERGEBNIS2 = 22.1 | ERGEBNISALT2 = 17.2 | PARTEI5 = Forum21 | ERGEBNIS5 = 11.0 | ERGEBNISALT5 = 13.2 | FARBE5 = 0000FF | PARTEI4 = FDP | ERGEBNIS4 = 17.0 | ERGEBNISALT4 = 10.9 | PARTEI6 = [[Klaus-Peter Puls|Puls]] | ERGEBNIS6 = 1.7 | ERGEBNISALT6 = 1.5 | FARBE6 = CCCCCC }} | rowspan="12" |{{Sitzverteilung | Land = DE | Überschrift = Sitzverteilung in der Stadtverordnetenversammlung | SPD|Grüne|Forum21|Puls|FDP|CDU| | Legende = ja | SPD = 6 | Grüne = 7 | Forum21 = 3 | Puls = 1 | FDP = 5 | CDU = 9 | Forum21 Farbe = 0000FF | Puls Farbe = CCCCCC | Puls Link = [[Klaus-Peter Puls|Puls]] }} |- style="text-align:right" | style="text-align:left" | CDU | style="text-align:left" | [[Christlich Demokratische Union Deutschlands]] | 27,5 | 9 | 30,7 | 10 | 33,6 | 13 |- style="text-align:right" | style="text-align:left" | SPD | style="text-align:left" | [[Sozialdemokratische Partei Deutschlands]] | 20,7 | 6 | 26,6 | 8 | 24,3 | 9 |- style="text-align:right" | style="text-align:left" | GRÜNE | style="text-align:left" | [[Bündnis 90/Die Grünen]] | 22,1 | 7 | 17,2 | 5 | 15,4 | 5 |- style="text-align:right" | Forum21 | Forum21 | 11,0 | 3 | 13,2 | 4 | 13,0 | 4 |- style="text-align:right" | style="text-align:left" | FDP | style="text-align:left" | [[Freie Demokratische Partei]] | 17,0 | 5 | 10,9 | 3 | 13,8 | 5 |- style="text-align:right" | style="text-align:left" | Puls | style="text-align:left" | Einzelbewerber [[Klaus-Peter Puls]]<ref>http://www.bergedorfer-zeitung.de/printarchiv/reinbek/article188444/Kommunalwahl-am-26-Mai-2013-Vorstellung-der-Reinbeker-Kandidaten-Wahlkreis-13.html</ref><ref>http://www.abendblatt.de/region/stormarn/article115057641/Klaus-Peter-Puls-tritt-aus-der-SPD-aus.html</ref> | 1,7 | 1 | 1,5 | 1 | — | — |- class="hintergrundfarbe5" style="text-align:right" | colspan="2" style="text-align:left" | '''gesamt''' | '''100,0''' | '''31''' | '''100,0''' | '''31''' | '''100,0''' | '''36''' |- ! colspan="2" style="text-align:left" | Wahlbeteiligung in % ! colspan="2" | ! colspan="2" | 45,5 ! colspan="2" | |} [[Datei:Reinbeker Rathaus.JPG|mini|Reinbeker Rathaus]] === Bürgermeister === <!-- Amtsvorgänger bitte mit Amtszeit und Partei nachtragen --> {| class="wikitable" ! colspan="2" | Amtszeit !! rowspan="2" | Name |- ! von !! bis |- | 17. Februar 1931 || 13. September 1945 | Eduard Claußen (NSDAP)<ref>[https://www.museumsverein-reinbek.de/wp-content/uploads/2018/06/Eduard-Claussen.pdf ''Eduard Claußen''], museumsverein-reinbek.de</ref><ref>Claußen half trotz seiner NSDAP-Zugehörigkeit im Rahmen seiner Möglichkeiten mehreren jüdischen Einwohnern und sorgte dafür, dass Reinbek kampflos den Engländern übergeben wurde, vgl. dazu: Detlev Landgrebe: Kückallee 37. Eine Kindheit am Rande des Holocaust. Rheinbach 2009, ISBN 978-3-87062-104-9, S. 163, S. 167 u.&nbsp;a.</ref> |- | 15. Dezember 1945 || 31. Januar 1946 || Wilhelm Kleist |- | 1. Februar 1946 || 22. September 1946 || Carl Dobbertin |- | 23. September 1946 || 11. November 1948 || Alwin Hemken |- | 12. November 1948 || 28. April 1950 || Carl Dobbertin |- | 28. April 1950 || 31. März 1951 || Wilhelm Kleist |- | 1. April 1951 || 31. Dezember 1971 || [[Hermann Körner]] |- | 1. Januar 1972 || 31. Januar 1990 || Günther Kock |- | 1. Februar 1990 || 31. Januar 1996 || Manfred Neumann |- | 1. September 1996 || 31. August 2008 || Detlef Palm |- | 1. September 2008 || 31. August 2014 || [[Axel Bärendorf]] |- | 1. September 2014 || || [[Björn Warmer]] |} === Wappen === [[Blasonierung]]: „In Rot ein silberner Wellenbalken, begleitet von drei im Dreipass mit den Stielen einander zugekehrten Eichenblättern, und zwar zwei oben und einem unten.“<ref>[{{SH-Wappenrolle|262|Stadt Reinbek, Kreis Stormarn|nurLink=1}} Kommunale Wappenrolle Schleswig-Holstein]</ref> Die Blätter, in ihrer Anordnung an das Wappen der Familie [[Bismarck (Adelsgeschlecht)|Bismarck]] angelehnt, versteht man als Symbole für den [[Sachsenwald]], während das Band für die [[Bille]] steht. Eine ähnliche Symbolik findet sich auf den Wappen der Nachbarorte [[Wohltorf]] und [[Aumühle]]; die Farben Rot und Weiß entsprechen den Wappen [[Holstein]]s und [[Kreis Stormarn|Stormarns]]. Das Wappen wurde 1935 genehmigt. === Städtepartnerschaften === * 1956–2011: Städtefreundschaft mit [[Täby]] ([[Schweden]]). Der Marktplatz in Reinbek-Klosterbergen, der ''Täbyplatz'', wurde nach der Partnerstadt benannt. * Seit 1961: Städtefreundschaft mit [[Königslutter am Elm]] ([[Niedersachsen]]). * Seit 1974: Patenschaft zwischen der [[Freiwillige Feuerwehr|Freiwilligen Feuerwehr]] Ohe und der Gemeinde [[Padasjoki]] ([[Finnland]]). * Seit 1999: Städtepartnerschaft mit [[Koło]] ([[Polen]]). == Kultur und Sehenswürdigkeiten == [[Datei:Das Reinbeker Schloss.jpg|mini|Reinbeker Schloss]] [[Datei:Museum Rade.JPG|mini|Ehemaliges Museum Rade]] === Theater, Kino und Museen === * Das Kultur- und Kongresszentrum ''Sachsenwald-Forum'' bietet ein wechselndes Programm von Tournee- und Privattheatern. * Der Filmring Reinbek e.&nbsp;V. führt ehrenamtlich monatlich eine Kinoveranstaltung in der Nathan-Söderblom-Kirche durch. * Das gegenüber vom Schloss gelegene ''Museum Rade'' stellte die Sammlung volkstümlicher Kunst des Hamburger Schriftstellers und Kunstsammlers [[Rolf Italiaander]] aus. Seit Sommer 2017 ist das Museum dauerhaft geschlossen, die Sammlung wurde Ende 2018 ins Schloss Reinbek verlegt [[Datei:Reinbek Sankt Maria Magdalena.JPG|hochkant|mini|Maria-Magdalenen-Kirche]] === Bauwerke === [[Datei:Reinbek dänenbrücke P4070041.JPG|mini|„Dänenbrücke“ von 1793]] [[Datei:RK 1810 P1650787 Bismarcksäule Friedrichsruh.jpg|mini|Bismarcksäule]] Verschont von den Zerstörungswellen des Zweiten Weltkrieges, zeigt Reinbeks Stadtarchitektur ein kontinuierliches Bild durch die Epochen norddeutscher Baugeschichte, angefangen bei der niederländischen Renaissance und alten Bauernkaten, über [[großbürger]]liche Villen der Kaiserzeit, Klinkerexpressionismus der Weimarer Republik und Wohngroßbauten der 1970er bis hin zu einer eher behutsamen Architektur der 1990er Jahre. * Ältestes und bedeutendstes Bauwerk ist das [[Schloss Reinbek]] im Stil der [[Niederländische Renaissance|Niederländischen Renaissance]]. [[Adolf I. (Schleswig-Holstein-Gottorf)|Herzog Adolf I. von Gottorf]] ließ das Schloss zwischen 1572 und 1576 in seiner heute noch vorhandenen Form errichten. Zunächst Nebenwohnsitz des Landesherren, war das Schloss in dänischer Zeit Residenz des Amtmannes und später kurzzeitig der Sitz des Landratsamtes für den [[Kreis Stormarn]]. Heute steht das originalgetreu restaurierte Gebäude für öffentliche Nutzung zur Verfügung. * Über die 1793 erbaute ''Dänenbrücke'', in unmittelbarer Nähe zum Schloss, verlief einst der Verkehr zwischen dem dänischen Amt Reinbek und dem [[Herzogtum Sachsen-Lauenburg]]. * Die ''Schönningstedter Mühle'', erbaut 1886, wurde seit der Stilllegung (1968) als Gaststätte betrieben. Sie wurde durch einen Brand (1991) vollständig zerstört. Sie wurde durch eine andere am Ursprungsort abgebaute auf den Grundmauern der Alten Mühle neu errichtet. * Die [[Bismarcksäule (Friedrichsruh)|Bismarcksäule]] auf dem ''Hammelsberg'' zwischen den Ortsteilen Krabbenkamp und Schönningstedt, in der Nähe des ehemaligen bismarckschen Guts Schönau, wurde 1903 fertiggestellt. Das 19 Meter hohe Monument entspricht dem üblichen Bismarcksäulen-Typus eines Feuerturmes, den [[Wilhelm Kreis]] 1898 entworfen hatte, und wurde aus Mitteln der deutschen Studentenschaft finanziert. Der Turm steht seit 1989 unter Denkmalschutz. * In Reinbek gibt es [[Liste der Stolpersteine in Reinbek|sieben Stolpersteine]] zur Erinnerung an Opfer des [[Nationalsozialismus]].<ref>[http://www.akens.org/akens/texte/stolpersteine/Stolpersteineliste.htm#Reinbek Stolpersteine: Reinbek]</ref> In der [[Liste der Kulturdenkmale in Reinbek]] stehen die in der Denkmalliste des Landes Schleswig-Holstein eingetragenen Kulturdenkmale. === Grünflächen und Naherholung === * Die Wald- und Wiesenlandschaft in und um Reinbek sowie der Schlosspark laden zum Spazieren, Wandern und Radfahren ein. Auf der Bille und auf dem Mühlenteich werden Kanufahrten veranstaltet. * Jährlich wird in Reinbek auf dem Täbyplatz oder am ''Waldhaus'' im Sommer oder im Herbst die sogenannte „Reinbeker Sommersause“ bzw. „Reinbeker Herbstsause“ gefeiert. Bei diesen Festen treten unter anderem regionale Musiker und Coverbands auf. === Sport === * Das ''Freizeitbad Reinbek'' und der angrenzende ''Sport-Park Reinbek'' bieten neben einem Hallenbad mit Außenschwimmbecken auch eine Sauna und verschiedene Sportprogramme an. * Die [[TSV Reinbek]] und der [[FC Voran Ohe]] bieten verschiedene Sportarten an. == Wirtschaft, Infrastruktur, öffentliche Einrichtungen == === Unternehmen === Reinbek zeichnet sich durch eine vielfältige, vorwiegend klein- und mittelständische Wirtschaftsstruktur aus. Zahlreiche bedeutende Firmen hatten bzw. haben hier ihren Sitz, wie zum Beispiel der [[Rowohlt Verlag]] (von 1960 bis März 2019), E.&nbsp;Michaelis & Co. – Papiergroßhandel, [[Almirall]] Almirall Hermal und [[Dermapharm|Allergopharma]] (die seit Mai 2021 an der Herstellung des Impfstoffs von [[Biontech]] beteiligt sind)<ref>[https://www.ndr.de/nachrichten/schleswig-holstein/coronavirus/Corona-Biontech-Impfstoff-kommt-jetzt-auch-aus-Reinbek,spahn290.html ''Corona: Biontech-Impfstoff kommt jetzt auch aus Reinbek''] {{Webarchive|url=https://web.archive.org/web/20220328133934/https://www.ndr.de/nachrichten/schleswig-holstein/coronavirus/Corona-Biontech-Impfstoff-kommt-jetzt-auch-aus-Reinbek,spahn290.html |date=2022-03-28 }}, ndr.de, 30. April 2021</ref>, [[Fürst-Bismarck-Quelle]], Grossmann-Feinkost, [[Kahl Gruppe|Amandus Kahl]] (Neuhaus Neotec), Peek&nbsp;&&nbsp;Cloppenburg (Verteilzentrum) und Lutz Aufzüge (Maschinen- und Anlagentechnik), Wollenhaupt (Teehandel). Ein weiterer großer Arbeitgeber ist das Krankenhaus Reinbek St. Adolf-Stift (Gesundheitswesen). Anfang der 1960er Jahre wurde das gemeinsame Gewerbegebiet Reinbek-[[Glinde]] erschlossen. Seitdem erfolgten immer wieder Erweiterungen und Neuausweisungen von Gewerbeflächen. Zuletzt wurde das Gewerbegebiet Haidland vermarktet (ca. 22&nbsp;ha): bis 2018 sind dort mehr als 30 Firmen angesiedelt worden, dadurch wurden 1200 Arbeitsplätze gesichert und ca. 400 neu geschaffen. Geplant ist die Erweiterung des Gewerbegebietes. Die wirtschaftliche Dynamik Reinbeks zeigt sich unter anderem in der Entwicklung der Gewerbebetriebe: deren Zahl stieg auf 2532 Betriebe (31. August 2018). Auch die positiven Arbeitsmarktdaten sind ein Beweis für die Besonderheit des Standortes. Im Geschäftsstellenbezirk der Arbeitsagentur Bad Oldesloe wird der Bezirk Reinbek mit einer der niedrigsten Arbeitslosenquoten aufgeführt, vergleichbar mit denen süddeutscher Wirtschaftsregionen. In der Region Südstormarn liegen einige der Kommunen mit der höchsten Kaufkraft in Deutschland. Auch Reinbek lag im Jahr 2017 mit einer Kaufkraftkennziffer von 118 über dem Durchschnitt (CIMA Lübeck, Jahresbericht interkommunales Einzelhandelsforum 2017). Reinbek ist perspektivisch weiter ein dynamischer Wirtschaftsstandort mit einer hohen Gewerbeflächennachfrage und steigenden Gewerbesteuereinnahmen, u.&nbsp;a. wegen der verkehrsgünstigen zentralen Lage in der Metropolregion direkt benachbart der Weltstadt Hamburg. Die Arbeitsplatzzentralität ist mit einem knapp 80-%-Anteil an den Beschäftigten hoch. === Öffentliche Einrichtungen === Reinbek ist Sitz eines [[Amtsgericht]]s. === Bildung === In Reinbek gibt es vier [[Grundschule]]n, eine [[Gemeinschaftsschule mit Oberstufe]] (mit auslaufenden Haupt- und Realschulklassen) und ein [[Sachsenwaldschule Gymnasium Reinbek|Gymnasium]]. Außerdem gibt es eine [[Förderschule (Deutschland)|Förderschule]]. Gemeinschaftsschule und Förderschule sind zum Schulzentrum Mühlenredder zusammengefasst. Die ''Volkshochschule Sachsenwald'' hat ein umfangreiches Angebot an Kursen verschiedener Fachrichtungen und deckt auch das Angebot für die Nachbargemeinde [[Wentorf bei Hamburg|Wentorf]] mit ab. Die meisten Kurse finden im eigenen, gut ausgestatteten Haus mitten in Reinbek statt. Die ''Reinbeker Stadtbibliothek'' bietet ein breit gefächertes Angebot aus alten wie neuen Medien und unterhält einen ständigen Bücherflohmarkt aus gespendeten und ausgemusterten Büchern. Seit 1989 besteht der [[Museumsverein Reinbek|Geschichts- und Museumsverein Reinbek e.&nbsp;V.]] === Verkehr === [[Datei:Reinbeker Bahnhof.jpg|mini|Der Reinbeker Bahnhof]] Reinbek liegt in der [[Metropolregion Hamburg]]. Von Reinbek ist die Hamburger Innenstadt mit der [[S-Bahn Hamburg|S-Bahn-Linie]] S&nbsp;21 in 25&nbsp;Minuten zu erreichen. Die S-Bahn verbindet Reinbek mit den Nachbarorten [[Wohltorf]] und [[Bahnhof Aumühle|Aumühle]], innerhalb Reinbeks fahren mehrere Buslinien, die von den zum [[Hamburger Verkehrsverbund|HVV]] gehörenden [[VHH PVG Unternehmensgruppe|VHH]] betrieben werden. Die Fernverkehrsstraßen [[Bundesstraße 5|B&nbsp;5]], [[Bundesautobahn 24|A&nbsp;24]] und [[Bundesautobahn 1|A&nbsp;1]] führen in die Hamburger Innenstadt bzw. in Richtung [[Berlin]], [[Lübeck]] und [[Bremen]]. Der nächstgelegene Fernbahnhof ist [[Bahnhof Hamburg-Bergedorf|Hamburg-Bergedorf]], die [[Bahnstrecke Hamburg–Berlin]] durchquert die Stadt ohne Halt parallel zur S-Bahn. == Persönlichkeiten == === Ehrenbürger === <!-- chronologisch nach Geburtsdatum geordnet --> {{Mehrspaltige Liste|liste= * [[Paul Lingens]] (1895–1976), Stadtverordneter der CDU, Bürgervorsteher * Karl Meißner (1912–2010), Stadtverordneter der SPD, Bürgervorsteher * [[Georges-Arthur Goldschmidt]] (* 1928), französisch-deutscher Schriftsteller, Essayist und Übersetzer * Lothar Zug (1928–2020), Stadtverordneter der CDU, Bürgervorsteher * Helmut Schomann (1932–2009), Stadtverordneter der SPD, Bürgervorsteher }} === Söhne und Töchter der Stadt === <!-- chronologisch nach Geburtsdatum geordnet --> {{Mehrspaltige Liste|liste= * [[Minna Specht]] (1879–1961), Pädagogin und Sozialistin * [[Wilhelm Bisse]] (1881–1946), Reichstagsabgeordneter der NSDAP * [[Horst Seifart]] (1916–2004), Journalist und Fernseh-Regisseur * [[Donat de Chapeaurouge]] (1925–2019), Kunsthistoriker * [[Georges-Arthur Goldschmidt]] (* 1928), französisch-deutscher Schriftsteller, Essayist und Übersetzer * Helmut Schomann (1932–2009), Politiker, Ehrenbürger und Träger des Bundesverdienstkreuzes * [[Hartmut Berg]] (* 1936), Wirtschaftswissenschaftler * [[Ekkehard Wachmann]] (* 1937), Entomologe * [[Wittko Francke]] (1940–2020), Chemiker * [[Hans Klapdor-Kleingrothaus]] (* 1942), Physiker * [[Klaus-Peter Puls]] (* 1943), Politiker * [[Albert Maringer]] (* 1945), Manager * [[Wolfgang Seifert (Japanologe)|Wolfgang Seifert]] (* 1946), Japanologe * [[Claus Peter Ortlieb]] (1947–2019), Mathematiker * [[Eckart Modrow]] (* 1948), Pädagoge und Sachbuchautor * [[Johannes Spallek]] (* 1948), Archivar und Kulturreferent * [[Christine Christ-von Wedel]] (* 1948), Historikerin * [[Dieter Matz]] (* 1948), Sportjournalist * [[Angela Sommer-Bodenburg]] (* 1948), Kinderbuchautorin und Malerin; bekannt wurde sie durch ihre Bücher über den ''Kleinen Vampir'' * [[Christel Hüttemann]] (* 1949), Trägerin des Bundesverdienstkreuzes * [[Mathias Nolte]] (* 1952), Buchautor und Journalist * [[Mathias Petersen]] (* 1955), Politiker * [[Harald Lemke (Politiker, 1956)|Harald Lemke]] (* 1956), Staatssekretär * [[Norbert Meier]] (* 1958), Fußballtrainer und ehemaliger -spieler * [[Sabine Sütterlin-Waack]] (* 1958), Rechtsanwältin und Politikerin (CDU) * [[Martin Rheinheimer]] (* 1960), Historiker * [[Jan van Aken (Politiker)|Jan van Aken]] (* 1961), Politiker * [[Dietrich Becker (Diplomat)|Dietrich Becker]] (* 1961), Diplomat * [[Ralf Sommer (Elektroingenieur)|Ralf Sommer]] (* 1961), Elektroingenieur * [[Thomas Röske]] (* 1962), Kunsthistoriker * [[Gerd Gottlob]] (* 1964), Journalist und Fußballkommentator * [[Gundula Bavendamm]] (* 1965), Historikerin und Kulturmanagerin * [[Christiane Bruns (Medizinerin)|Christiane Bruns]] (* 1965), Chirurgin * [[Kerstin Drechsel]] (* 1966), Malerin * [[Andreas Herbig]] (1966–2022), Produzent, Echopreisträger * [[Birte Karalus]] (* 1966), Journalistin und Moderatorin * [[Lena Johannson]] (* 1967), Schriftstellerin * [[Michael Meyer-Hermann (Physiker)|Michael Meyer-Hermann]] (* 1967), Physiker und Hochschullehrer * [[Thorsten Schröder]] (* 1967), Journalist, Moderator und Sprecher der Tagesschau * [[Lars Uwe Höltich]] (* 1968), TV-Producer * [[Sönke Lieberam-Schmidt]] (* 1969), Wirtschaftsinformatiker und Professor * [[Heiko Nieder]] (* 1972), Koch, mit zwei Sternen im ''Guide Michelin'' ausgezeichnet * [[Christine Berger]] (* 1973), Theater- und Fernsehschauspielerin * [[Andreas Dobberkau]] (* 1975), Schauspieler * [[Helmut Fritz]] (* 1975), fiktiver Popsänger * [[Julian Krafftzig]] (* 1977), Radiomoderator * [[Torben Liebrecht]] (* 1977), Schauspieler, Regisseur und Drehbuchautor * [[Alexander Nerlich]] (* 1979), Regisseur * [[Imke Wedekind]] (* 1984), Volleyballspielerin * [[Ann-Kathrin Karschnick]] (* 1985), Fantasy-Autorin * [[Max Kruse (Fußballspieler)|Max Kruse]] (* 1988), Fußballspieler * [[Marvin Boadu]] (* 1989), Basketballspieler * [[Felix Brügmann]] (* 1992), Fußballspieler * [[Maximilian Buhk]] (* 1992), Automobilrennfahrer * [[Felix von der Laden]] (* 1994), Webvideoproduzent (bekannt als „Dner“), Automobilrennfahrer und Unternehmer * [[Sina Aylin Demirhan]] (* 1994), Politikerin (Bündnis 90/Die Grünen) * [[Larina Aylin Hillemann]] (* 1996), Ruderin * [[Victoria Helene Bergemann]] (* 1997), Komikerin und Autorin * [[Noma Noha Akugue]] (* 2003), Tennisspielerin }} === Mit Reinbek verbunden ===<!-- chronologisch nach Geburtsdatum geordnet --> {{Mehrspaltige Liste|liste= * [[Georg Julius Andresen]] (1815–1882), Autor, Mediziner, Hydrotherapeut und Gründer des Sophienbads * [[Arthur Goldschmidt (Jurist)|Arthur Goldschmidt]] (1873–1947), Jurist und Politiker * [[Hans E. B. Kruse]] (1891–1968), Kaufmann und Hamburger Senator, wohnte und starb in Reinbek * [[Franz Heske]] (1892–1963), Forstwissenschaftler * [[Bernhard Rogge (Marineoffizier)|Bernhard Rogge]] (1899–1982), Admiral * [[Helene Francke-Grosmann]] (1900–1990), Forstwissenschaftlerin * [[Erwin Freytag]] (1907–1987), Autor und evangelisch-lutherischer Theologe * [[Heinrich Maria Ledig-Rowohlt]] (1908–1992), bis 1982 Verleger des [[Rowohlt Verlag]]s * [[Rolf Italiaander]] (1913–1991), Schriftsteller, Übersetzer, Forschungsreisender, Ethnograf * [[Sandro von Lorsch]] (1919–1992), Maler * [[Arwed Imiela]] (1929–1982), Frauenmörder * [[Günter Gaus]] (1929–2004), Journalist, Publizist, Diplomat und Politiker * [[Hans-Jürgen von Maydell]] (''Baron Maydell''; 1932–2010), Forstwissenschaftler * [[Heinz-Georg Keerl]] (1946–2011), General * [[Thomas Straubhaar]] (* 1957), Ökonom * [[Holger Waldenberger]] (* 1967), Quizspieler * [[Bjarne Mädel]] (* 1968), Schauspieler * [[Moritz Bleibtreu]] (* 1971), Schauspieler * [[Ann-Katrin Schröder]] (* 1973), Journalistin und Fernsehmoderatorin * [[Bodo Wartke]] (* 1977), Musik-Kabarettist * [[Martin Habersaat]] (* 1977), Politiker, lebt seit 2014 in Reinbek * [[Julian Reister]] (* 1986), Tennisspieler }} == Literatur == ;Antiquarisch * Mathilde Weise-Minck: ''Kindertage in Reinbek.'' Piper, München 1947, {{DNB|576902853}}. * Curt Davids: ''Festschrift zur 725-Jahrfeier von Reinbek.'' 1963, {{DNB|451252543}}. * Walter Fink: ''Das Amt Reinbek.'' Zentralstelle f. Personen- u. Familiengeschichte, Frankfurt am Main 1969, {{DNB|999410660}}. * Herbert Rathmann: ''Ich bin ein Reinbeker.'' 1978, {{OCLC|248265316}}. * Curt Davids: ''Die Wassermühle in Reinbek.'' 1982, {{DNB|840196717}}. * Hans Heuer: ''Das Kloster Reinbek.'' Beitrag zur Geschichte der Landschaft Stormarn. Wachholtz, Neumünster 1985, ISBN 3-529-02186-5. * [[Dirk Bavendamm]]: ''Reinbek. Geschichte einer holsteinischen Stadt zwischen Hamburg und Sachsenwald.'' 1988, ISBN 3-9801817-0-7. * ''Reinbek in alten Ansichten.'' Bildband. Europäische Bibliothek, Zaltbommel 1996, ISBN 90-288-6082-7. ;Aktuellere Titel * Wolf Gütschow, Michael Zapf: ''Reinbek und der Sachsenwald im Wandel.'' Bildband. Schubert, Hamburg 1997, ISBN 3-929229-44-7. * ''Reinbek gestern und heute.'' Bildband. Europäische Bibliothek, Zaltbommel 2000, ISBN 90-288-6634-5. * Georges-Arthur Goldschmidt: ''Ein Garten in Deutschland.'' 2000, ISBN 3-250-10118-4. * Frank Göhre: ''Endstation Reinbek.'' Krimi. Hamburger Abendblatt, Hamburg 2001, ISBN 3-921305-20-9. * Antje Wendt: ''Das Schloß Reinbek.'' Wachholtz, Neumünster 1994, ISBN 3-529-02739-1. * Detlev Landgrebe: ''Kückallee 37: Eine Kindheit am Rande des Holocaust.'' CMZ, Rheinbach 2009, ISBN 978-3-87062-104-9. == Weblinks == {{Commonscat}} {{Wikivoyage}} * [https://www.reinbek.de/ Website der Stadt Reinbek] == Einzelnachweise == <references /> {{NaviBlock |Navigationsleiste Städte und Gemeinden im Kreis Stormarn |Navigationsleiste Stadtteile von Reinbek}} {{Normdaten|TYP=g|GND=4049222-9|LCCN=n50052582|VIAF=312788140}} [[Kategorie:Ort im Kreis Stormarn]] [[Kategorie:Ort an der Bille]] [[Kategorie:Reinbek| ]] [[Kategorie:Ersterwähnung 1238]] [[Kategorie:Stadt in Schleswig-Holstein]] [[Kategorie:Stadtrechtsverleihung 1952]] 662mj3g32r6t7m0uw1b3ydmnt611kvz Test:RandomGeoTest3477 0 166053 739040 657022 2026-04-21T20:10:56Z WBrown (WMF) 58818 Test 739040 wikitext text/x-wiki Potato.Test 0ms27azt44xztn20p38xcdkfjz7loa8 User:Iniquity/edithere-core.js 2 167481 739043 669875 2026-04-21T22:48:17Z MusikAnimal 24817 CodeMirror v6 modules have been moved ([[phab:T373720]]) 739043 javascript text/javascript // Quick Edit gadget // Edit sections of a page without leaving the article // Based on [[:en:w:User:BrandonXLF/QuickEdit]] by [[:en:w:User:BrandonXLF]] // Some changes from [[meta:User:Jack who built the house/editHere.js]] by [[meta:User:Jack who built the house]] // Extra functions and refactoring by [[meta:Iniquity]] (function () { let mobile = mw.config.get('skin') === 'minerva'; let titleRegexp = new RegExp( mw.config.get('wgArticlePath').replace(/[.*+?^${}()|[\]\\]/g, '\\$&').replace(/\\\$1/, '([^?]+)') + '|[?&]title=([^&#]*)' ); let apiSingleton; function api(func, params) { if (!apiSingleton) { apiSingleton = new mw.Api(); } $.extend(params, { errorformat: 'html', errorlang: mw.config.get('wgUserLanguage'), errorsuselocal: true }); return apiSingleton[func](params).fail(function (_, data) { mw.notify(apiSingleton.getErrorMessage(data), { type: 'error', tag: 'qe' }); }); } function getPageInfo(title, sectionID) { return api('get', { action: 'query', curtimestamp: 1, prop: 'revisions', indexpageids: 1, titles: title, rvprop: ['timestamp', 'content'], rvslots: 'main', rvsection: sectionID }).then(function (res) { let rev = res.query.pages[res.query.pageids[0]].revisions[0]; return { start: res.curtimestamp, base: rev.timestamp, full: rev.slots.main['*'] }; }); } function getPreviewCallback(editor) { editor.children('.preview').remove(); // -- Minimal, library-agnostic preview progress indicator $('<div>') .addClass('qe-progress-bar') .text('Loading preview…') .appendTo(editor); return function (html) { editor.children('.preview').remove(); editor.children('.qe-progress-bar').remove(); const $preview = $('<div>') .html(html) .addClass('qe-border-color-base qe-preview-block') .addClass('preview') .appendTo(editor); mw.hook('wikipage.content').fire($preview); }; } function showCompare(editor, title, from, to) { mw.loader.load('mediawiki.diff.styles'); api('post', { action: 'compare', fromslots: 'main', 'fromtext-main': from, fromtitle: title, frompst: 'true', toslots: 'main', 'totext-main': to, totitle: title, topst: 'true' }).then(function (r) { return r.compare['*'] ? $('<table>').addClass('diff').append( $('<colgroup>').append( $('<col>').addClass('diff-marker'), $('<col>').addClass('diff-content'), $('<col>').addClass('diff-marker'), $('<col>').addClass('diff-content') ) ).append(r.compare['*']) : mw.msg('diff-empty'); }).then(getPreviewCallback(editor)); } // Parts taken from EditPage::extractSectionTitle and Parser::stripSectionName function getSectionSummary(text) { let match = text.match(/^(=+)(.+)\1\s*(\n|$)/); return !match ? '' : '/* ' + match[2].trim() // Strip internal link markup .replace(/\[\[:?([^[|]+)\|([^[]+)\]\]/g, '$2') .replace(/\[\[:?([^[]+)\|?\]\]/g, '$1') // Strip external link markup .replace(new RegExp('\\[(?:' + mw.config.get('wgUrlProtocols') + ')([^ ]+?) ([^\\[]+)\\]', 'ig'), '$2') // Remove wikitext quotes .replace(/(''|'''|''''')(?!')/g, '') // Strip HTML tags .replace(/<[^>]+?>/g, '') + ' */ '; } async function showEditor($element) { let progress = $('<div>').addClass('qe-progress-bar').text('Loading…'); // https://www.mediawiki.org/wiki/Heading_HTML_changes // Cannot use .closest() because DiscussionTools nests an h2 within a .mw-heading let heading = $element.parents(':header, .mw-heading').last(); let matcher = heading.nextUntil.bind(heading); let inserter = heading.after.bind(heading); let targetEl = $element.siblings('.qe-target').last(); let titleMatch = targetEl.attr('href').match(titleRegexp); let title = decodeURIComponent(titleMatch[1] || titleMatch[2]); let sectionID = /[?&]v?e?section=T?-?(\d*)/.exec(targetEl.attr('href'))[1]; if (!heading.closest('.mw-parser-output').length) { let $articleContent = $('#mw-content-text .mw-parser-output'); matcher = function (selector) { let $child = $articleContent.children(selector).first(); if ($child.length) { return $child.prevAll(); } return $articleContent.children(); }; inserter = $articleContent.prepend.bind($articleContent); } inserter(progress); $element.addClass('qe-loading'); $('.qe-hide').removeClass('qe-hide'); $('.qe-heading').removeClass('qe-heading'); $('#qe-editor').remove(); getPageInfo(title, sectionID).then(async function (r) { await (new mw.Api()).loadMessages([ 'publishchanges', 'tooltip-publish', 'accesskey-publish', 'showpreview', 'tooltip-preview', 'accesskey-preview', 'showdiff', 'tooltip-diff', 'accesskey-diff', 'cancel', 'word-separator', 'brackets', 'diff-empty', 'summary', 'minoredit', 'summary-preview' ]); var start = r.start, base = r.base, full = r.full, saving = false, expanded = false, remainderStart = full.match(/\n=+.+=+(?:\n|$)/), part = remainderStart ? full.substring(0, remainderStart.index) : full, remainder = remainderStart ? full.substring(remainderStart.index) : '', level = 0, editor; full.replace(/^(=+).+?(=+)(?:\n|$)/, function (m, a, b) { level = Math.min(a.length, b.length); return m; }); var levelMatch = 'h1'; for (var i = 2; i <= level; i++) levelMatch += ', h' + i + ':has(*), .mw-heading' + i; var partSection = matcher(':header:has(*), .mw-heading'), fullSection = matcher(levelMatch), // -- Native textarea to keep WikiEditor/CodeMirror compatibility $textarea = $('<textarea>') .addClass('qe-textarea') .val(part), // -- Summary input $summaryInput = $('<input>') .attr('type', 'text') .addClass('qe-summary-input') .val(getSectionSummary(part)); // -- Shim objects for existing integrations expecting OOUI-like shape var textareaShim = { $input: $textarea, $element: $textarea }; var summaryShim = { $input: $summaryInput, $element: $summaryInput }; // -- Will render Codex buttons later via Vue partSection.addClass('qe-hide'); heading.addClass('qe-heading'); $element.removeClass('qe-loading'); progress.remove(); $textarea.addClass('qe-textarea'); $summaryInput.on('keydown', function (e) { if (e.key === 'Enter') { e.preventDefault(); if (typeof window.__qeCodexActions !== 'undefined' && window.__qeCodexActions.onSave) { window.__qeCodexActions.onSave(); } } }); function handleSave() { if (saving) return; var fullText = $textarea.val() + (expanded ? '' : remainder); saving = true; api('postWithEditToken', { action: 'edit', title: title, section: sectionID, summary: $summaryInput.val(), text: fullText, minor: window.__qeCodexState && window.__qeCodexState.minor ? true : undefined, notminor: window.__qeCodexState && window.__qeCodexState.minor ? undefined : true, starttimestamp: start, basetimestamp: base }).then(function () { api('get', { action: 'parse', page: mw.config.get('wgPageName'), prop: ['text', 'categorieshtml'] }).then(function (r) { var contentText = $('#mw-content-text'), catLinks = $('#catlinks'); contentText.find('.mw-parser-output').replaceWith(r.parse.text['*']); mw.hook('wikipage.content').fire(contentText); catLinks.replaceWith(r.parse.categorieshtml['*']); mw.hook('wikipage.categories').fire(catLinks); // -- Clean up WikiEditor and CodeMirror after successful save if (typeof $textarea.wikiEditor === 'function') { try { var $cmWrapper = $textarea.closest('.ext-codemirror-wrapper'); if ($cmWrapper.length) { var cmInstance = $cmWrapper.data('cmInstance'); if (cmInstance && typeof cmInstance.destroy === 'function') { cmInstance.destroy(); } } $textarea.wikiEditor('destroy'); } catch (e) { console.error('Error destroying WikiEditor/CodeMirror after save:', e); } } // -- Remove editor and restore page layout after successful save if (window.__qeCodexApp && window.__qeCodexApp.unmount) { try { window.__qeCodexApp.unmount(); } catch (e) {} window.__qeCodexApp = null; } editor.remove(); heading.removeClass('qe-heading'); fullSection.removeClass('qe-hide'); // -- Signal the editor is closing if (window.qeIntegrations && typeof window.qeIntegrations.onEditorClose === 'function') { window.qeIntegrations.onEditorClose(); } saving = false; }); }, function (code) { if (code == 'editconflict') { showEditConflict(editor, title, sectionID, fullText).then(function (r) { start = r.start; base = r.base; // -- r.textarea is a jQuery element now $textarea = r.textarea; expanded = true; }); } saving = false; }); } function handlePreview() { let summaryValue = $summaryInput.val(); // Split summary into section and rest text let sectionMatch = summaryValue.match(/^\/\*\s*([^*]+?)\s*\*\/(.*)$/); let summaryHtml = ''; if (sectionMatch) { const section = sectionMatch[1].trim(); const rest = sectionMatch[2] ? sectionMatch[2].trimStart() : ''; const anchor = '#' + section.replace(/ /g, '_'); // Generate HTML for link to section with comment and arrow summaryHtml = '<span class="comment"><span class="autocomment">&#8594;<a href="' + anchor + '"><bdi dir="ltr">' + section + '</bdi></a>: </span>'; // Parse only rest text const restParsePromise = api('post', { action: 'parse', title: title, prop: 'text', pst: 'true', disablelimitreport: 'true', disableeditsection: 'true', sectionpreview: 'true', disabletoc: 'true', text: rest }); const mainPreviewPromise = api('post', { action: 'parse', title: title, prop: 'text', pst: 'true', disablelimitreport: 'true', disableeditsection: 'true', sectionpreview: 'true', disabletoc: 'true', text: $textarea.val() }); Promise.all([restParsePromise, mainPreviewPromise]).then(function ([restRes, mainRes]) { // Remove outer <div> using jQuery or regex let restHtml = restRes.parse.text['*']; if (restHtml.startsWith('<div')) { // jQuery preferred if available try { restHtml = $(restHtml).html(); } catch (e) { restHtml = restHtml.replace(/^<div[^>]*>[\s\n\r]*<p>/, '<div>').replace(/<\/p>[\s\n\r]*<\/div>$/, '</div>'); } } // Remove only outer <p>...</p> if it wraps the entire result restHtml = restHtml.replace(/^<p>([\s\S]*)<\/p>$/i, '$1'); const summaryPreviewHtml = '<div class="qe-summary-preview qe-border-color-base">' + '<b>' + mw.msg('summary-preview') + '</b><br>' + summaryHtml + restHtml + '</span>' + '</div>'; const mainPreviewHtml = mainRes.parse.text['*'] + '<div style="clear:both;"></div>'; return summaryPreviewHtml + mainPreviewHtml; }).then(getPreviewCallback(editor)); } else { // No pattern /* ... */ — parse as wikitext const summaryParsePromise = api('post', { action: 'parse', title: title, prop: 'text', pst: 'true', disablelimitreport: 'true', disableeditsection: 'true', sectionpreview: 'true', disabletoc: 'true', text: summaryValue }); const mainPreviewPromise = api('post', { action: 'parse', title: title, prop: 'text', pst: 'true', disablelimitreport: 'true', disableeditsection: 'true', sectionpreview: 'true', disabletoc: 'true', text: $textarea.val() }); Promise.all([summaryParsePromise, mainPreviewPromise]).then(function ([summaryRes, mainRes]) { const summaryPreviewHtml = '<div class="qe-summary-preview qe-border-color-base">' + '<b>' + mw.msg('summary-preview') + '</b><br>' + '<span class="comment">' + summaryRes.parse.text['*'] + '</span>' + '</div>'; const mainPreviewHtml = mainRes.parse.text['*'] + '<div style="clear:both;"></div>'; return summaryPreviewHtml + mainPreviewHtml; }).then(getPreviewCallback(editor)); } } function handleCompare() { showCompare(editor, title, part + (expanded ? remainder : ''), $textarea.val()); } function handleCancel() { // -- Clean up WikiEditor and CodeMirror before removing the editor if (typeof $textarea.wikiEditor === 'function') { try { var $cmWrapper = $textarea.closest('.ext-codemirror-wrapper'); if ($cmWrapper.length) { var cmInstance = $cmWrapper.data('cmInstance'); if (cmInstance && typeof cmInstance.destroy === 'function') { cmInstance.destroy(); } } $textarea.wikiEditor('destroy'); } catch (e) { console.error('Error destroying WikiEditor/CodeMirror:', e); } } if (window.__qeCodexApp && window.__qeCodexApp.unmount) { try { window.__qeCodexApp.unmount(); } catch (e) {} window.__qeCodexApp = null; } editor.remove(); heading.removeClass('qe-heading'); fullSection.removeClass('qe-hide'); if (window.qeIntegrations && typeof window.qeIntegrations.onEditorClose === 'function') { window.qeIntegrations.onEditorClose(); } } function handleMore() { expanded = true; $textarea.val($textarea.val() + remainder); // Step-by-step height debugging: find the first .ext-codemirror-wrapper on the page var $wrapper = $('.ext-codemirror-wrapper').first(); setTimeout(function() { var $textarea = $wrapper.find('textarea'); if ($textarea.length) { var height = $textarea.outerHeight(); var $nextDiv = $textarea.next('div'); if ($nextDiv.length) { $nextDiv.height(height); $nextDiv.css('height', height + 'px'); $nextDiv[0].style.setProperty('height', height + 'px', 'important'); } } }, 5); fullSection.addClass('qe-hide'); } editor = $('<div id="qe-editor">').append( $('<div>').addClass('qe-editor-block qe-background-color-interactive qe-color-base qe-border-color-base').append( $textarea, $('<div>').addClass('qe-edit-options').append( $('<div id="wpSummaryWidget">').addClass('qe-border-color-base').append( $('<div>').html(mw.message('summary').parse()), $summaryInput ), $('<div id="qe-codex-buttons">').addClass('qe-buttons qe-border-color-base'), title !== mw.config.get('wgPageName') ? $('<div>').addClass('qe-not-current-page qe-border-color-base').append( 'Editing page: ', $('<a>').attr('href', mw.config.get('wgArticlePath').replace('$1', title)).addClass('qe-not-current-page-link').text(title.replace(/_/g, ' ')) ) : undefined ) ) ); inserter(editor); // Initialize WikiEditor with CodeMirror for the native textarea mw.loader.using([ 'ext.wikiEditor', 'ext.CodeMirror.WikiEditor', 'ext.CodeMirror.mode.mediawiki' ]).then(function(require) { if (typeof mw.addWikiEditor === 'function') { try { mw.addWikiEditor($textarea); $textarea.wikiEditor({ toolbar: { format: {}, insert: {}, advanced: {} } }); const CodeMirrorWikiEditor = require('ext.CodeMirror.WikiEditor'); const mediawikiLang = require('ext.CodeMirror.mode.mediawiki'); const cmWe = new CodeMirrorWikiEditor($textarea[0], mediawikiLang()); cmWe.mode = 'mediawiki'; // Явно указываем mode для совместимости с CodeMirrorWikiEditor cmWe.initialize(); } catch (e) { console.error('[qe] Error initializing WikiEditor with CodeMirror:', e); } } // Force integration call via setTimeout setTimeout(function() { if (window.qeIntegrations && typeof window.qeIntegrations.applyExternalIntegrations === 'function') { window.qeIntegrations.applyExternalIntegrations(textareaShim, summaryShim); } else { console.warn('[qe] qeIntegrations or applyExternalIntegrations not found'); } }, 50); }).catch(function(error) { console.error('[qe] Failed to load WikiEditor, CodeMirror, or Wikificator:', error); }); // Integration of external tools via hook $textarea.on('wikiEditor-toolbar-done', function () { if (window.qeIntegrations && typeof window.qeIntegrations.applyExternalIntegrations === 'function') { window.qeIntegrations.applyExternalIntegrations(textareaShim, summaryShim); } else { console.warn('[qe] qeIntegrations or applyExternalIntegrations not found'); } }); // Fix cases when editing a section next to two floating images like at // https://en.wikipedia.org/w/index.php?title=Elevation&oldid=1235703526#Aviation // -- No updatePosition for native textarea // -- Render Codex controls (load full Codex bundle for gadgets/userscripts) mw.loader.using('@wikimedia/codex').then(function (require) { const Vue = require('vue'); const CodexLib = require('@wikimedia/codex'); const { CdxButton, CdxCheckbox, CdxButtonGroup, CdxProgressBar } = CodexLib || {}; try { console.log('[qe] Codex exports:', Object.keys(CodexLib || {})); } catch (e) {} var app = Vue.createMwApp({ data: function () { return { isSaving: false, canMore: part !== full && !expanded, minor: false, labels: { minoredit: mw.msg('minoredit'), publish: mw.msg('publishchanges'), preview: mw.msg('showpreview'), diff: mw.msg('showdiff'), cancel: mw.msg('cancel') } }; }, methods: { onSave: function () { if (this.isSaving) return; this.isSaving = true; window.__qeCodexState.minor = this.minor; handleSave(); // Saving state will be reset after parse setTimeout(() => { this.isSaving = false; }, 1000); }, onPreview: function () { handlePreview(); }, onCompare: function () { handleCompare(); }, onCancel: function () { handleCancel(); }, onMore: function () { handleMore(); this.canMore = false; } }, template: ` <div class="qe-buttons qe-border-color-base"> <div style="margin-bottom:6px"><cdx-checkbox v-model="minor">{{ labels.minoredit }}</cdx-checkbox></div> <div class="qe-cdx-buttons-row" style="display:flex;gap:6px;flex-wrap:wrap;align-items:center;"> <cdx-button :disabled="isSaving" action="progressive" weight="primary" @click="onSave">{{ labels.publish }}</cdx-button> <cdx-button :disabled="isSaving" @click="onPreview">{{ labels.preview }}</cdx-button> <cdx-button :disabled="isSaving" @click="onCompare">{{ labels.diff }}</cdx-button> <cdx-button :disabled="isSaving" weight="quiet" action="destructive" @click="onCancel">{{ labels.cancel }}</cdx-button> <cdx-button v-if="canMore" :disabled="isSaving" @click="onMore" title="Edit the entire section (including subsections)">+</cdx-button> </div> <cdx-progress-bar v-if="isSaving" class="qe-progress-bar" /> </div> ` }); // Register Codex plugin and components explicitly for reliability try { app.use(CodexLib); } catch (e) {} try { if (CdxButton) { app.component('CdxButton', CdxButton); app.component('cdx-button', CdxButton); } if (CdxCheckbox) { app.component('CdxCheckbox', CdxCheckbox); app.component('cdx-checkbox', CdxCheckbox); } if (CdxButtonGroup) { app.component('CdxButtonGroup', CdxButtonGroup); app.component('cdx-button-group', CdxButtonGroup); } if (CdxProgressBar) { app.component('CdxProgressBar', CdxProgressBar); app.component('cdx-progress-bar', CdxProgressBar); } } catch (e) {} window.__qeCodexState = { minor: false }; window.__qeCodexActions = { onSave: function () { try { if (window.__qeCodexApp && window.__qeCodexApp._instance && window.__qeCodexApp._instance.proxy) { window.__qeCodexApp._instance.proxy.onSave(); } else { handleSave(); } } catch (e) { handleSave(); } } }; window.__qeCodexApp = app; app.mount('#qe-codex-buttons'); // Fallback: if buttons are missing or invisible, append HTML buttons (do not remove checkbox) setTimeout(function () { var host = document.getElementById('qe-codex-buttons'); if (!host) return; var codexBtn = host.querySelector('.cdx-button'); var visible = codexBtn && codexBtn.offsetWidth > 0 && codexBtn.offsetHeight > 0 && getComputedStyle(codexBtn).visibility !== 'hidden'; if (!visible) { console.warn('[qe] Codex buttons not detected or invisible, rendering HTML fallback'); function makeBtn(text, onClick, extraStyle) { var b = document.createElement('button'); b.setAttribute('data-qe-fallback', ''); b.type = 'button'; b.textContent = text; b.style.marginRight = '6px'; if (extraStyle) Object.assign(b.style, extraStyle); b.addEventListener('click', onClick); return b; } var bar = document.createElement('div'); bar.style.marginTop = '6px'; bar.appendChild(makeBtn(mw.msg('publishchanges'), handleSave, { fontWeight: '600' })); bar.appendChild(makeBtn(mw.msg('showpreview'), handlePreview)); bar.appendChild(makeBtn(mw.msg('showdiff'), handleCompare)); bar.appendChild(makeBtn(mw.msg('cancel'), handleCancel)); if (part !== full && !expanded) { bar.appendChild(makeBtn('+', function () { handleMore(); })); } host.appendChild(bar); } }, 250); }); }, function () { $element.removeClass('qe-loading'); progress.remove(); }); } // FIXIT: It is necessary to rework it to call the standard MediaWiki interface, it can also be done in an iframe function showEditConflict(editor, title, sectionID, text) { return getPageInfo(title, sectionID).then(function (r) { var $left = $('<textarea>') .addClass('qe-textarea') .val(r.full), $right = $('<textarea>') .addClass('qe-textarea') .val(text); function syncSize() { var height = Math.max($left.outerHeight(), $right.outerHeight()); $left.height(height); $right.height(height); } editor.find('> :first-child > :first-child').remove(); $('<table>').addClass('qe-border-color-base').css({ width: '100%', borderWidth: '1px', borderStyle: 'solid', borderBottom: 'none', borderSpacing: '0', margin: '0 !important' }).append( $('<tr>').append( $('<th>').addClass('qe-table-th') .text('Their version (to be saved)'), $('<th>').css({ width: '50%', paddingTop: '4px' }).text('Your version') ), $('<tr>').append( $('<td>').css({ width: '50%', padding: '4px 4px 0 8px' }).append( $left.css({ width: '100%', maxWidth: '100%', fontFamily: 'monospace, monospace' }) ), $('<td>').css({ width: '50%', padding: '4px 8px 0 4px' }).append( $right.css({ width: '100%', maxWidth: '100%', fontFamily: 'monospace, monospace' }) ) ) ).prependTo(editor.find('> :first-child')); $left.on('input', syncSize); $right.on('input', syncSize); syncSize(); showCompare(editor, title, text, r.full); r.textarea = $left; return r; }); } function clickHandler(event) { const $element = $(event.target).closest('.qe-editlink'); if (!$element.length || $element.hasClass('qe-loading')) return; event.preventDefault(); showEditor($element); } $.when($.ready).done(function () { const $body = $(document.body); $body.on('click', clickHandler); }); })(); odbt5u9zfwx6bxyru7cpic4smezhxwe Portugal in the Junior Eurovision Song Contest 0 168785 739047 681512 2026-04-21T23:15:28Z ~2026-24671-15 73651 Add additional test copy 739047 wikitext text/x-wiki Test change i33uiyz4eplv15g26atp4vdu7dkf350 739048 739047 2026-04-21T23:16:27Z ~2026-24671-15 73651 Remove change 739048 wikitext text/x-wiki Test bop1vj5i98maix36pjrpgep1w6hnxfe 739049 739048 2026-04-21T23:22:55Z ~2026-24653-43 73652 added 1 to test hcaptcha 739049 wikitext text/x-wiki Test1 hz8wwmgnqpczk13kff6qt0cmp5aj291 User:Ponor/wAwB-worker.js 2 171632 739044 738852 2026-04-21T22:48:40Z MusikAnimal 24817 CodeMirror v6 modules have been moved ([[phab:T373720]]) 739044 javascript text/javascript /* * wAwB – An in-browser application for automated editing of wiki pages. * Features: customizable regex or JavaScript search-and-replace rules, * custom JavaScript pre/post-processing functions and function libraries, * granular protection or targeting of different parts of wikitext, * a full-fledged CodeMirror editor, and options to move, delete, and protect pages. * Author: [[User:Ponor]] * Documentation: [[User:Ponor/wAwB]] * License: GNU General Public License (GPL) */ //<nowiki> mw.loader.using([ 'oojs-ui-core', 'oojs-ui-widgets', 'oojs-ui-windows', 'mediawiki.api', 'mediawiki.diff.styles', 'mediawiki.util', 'oojs-ui.styles.icons-content', 'oojs-ui.styles.icons-interactions', 'oojs-ui.styles.icons-movement', 'oojs-ui.styles.icons-moderation', 'oojs-ui.styles.icons-editing-core', 'oojs-ui.styles.icons-editing-advanced' ]).then(function() { // ===================================================================== // 1. STATE & CONFIGURATION // ===================================================================== var SCRIPT_TIMEOUT_MS = window.wa_timeout || 5000; var FETCH_SAFETY_LIMIT = window.wa_fetchLimit || 10000; var APP_NAME = "wAwB"; var DO_TAG = false; var SUMMARY_SUFFIX = window.wa_suffix || " [[:en:User:Ponor/wAwB| #wAwB]]"; var APP_VERSION = "0.6"; var DOC_URL = window.wa_docUrl || "https://en.wikipedia.org/wiki/User:Ponor/wAwB"; document.title = window.wa_editIn || "Edit in wAwB"; var PERMS = { canSave: false, allowBot: false, saveDelay: 0 }; var IS_ADMIN = mw.config.get('wgUserGroups').includes('sysop'); var CAN_MOVE = IS_ADMIN || mw.config.get('wgUserGroups').includes('extendedmover') || mw.config.get('wgUserGroups').includes('filemover') || mw.config.get('wgUserGroups').includes('pagemover'); var WIKI = mw.config.get('wgDBname'); var SAVED_RUN = 0; var SAVED_SESSION = 0; var currentPageExists = false; var isRunning = false; var isFetching = false; var currentTitle = null; var currentVars = {}; var currentLibrary = { name: null, code: null }; var originalWikitext = ""; var baseRevId = 0; var currentViewMode = 'diff'; var autoSaveTimer = null; var propNamesLoaded = false; var hasNewSources = false; var currentHeightMode = 1; // 0=25%, 1=45% (default), 2=72% var heightValues = ['25%', '45%', '72%']; // EXTERNAL RULES STATE var wikiTypos = []; var localTypos = []; // LOADING FLAG var isLoadingProject = false; // NAMESPACE ALIASES var nsIds = mw.config.get('wgNamespaceIds'); var catAliases = [], fileAliases = []; for (var key in nsIds) { if (nsIds[key] === 14) catAliases.push(key.replace(/_/g, ' ')); if (nsIds[key] === 6) fileAliases.push(key.replace(/_/g, ' ')); } catAliases.sort((a, b) => b.length - a.length); fileAliases.sort((a, b) => b.length - a.length); var REGEX_CAT_PFX = catAliases.map(mw.util.escapeRegExp).join('|'); var REGEX_FILE_PFX = fileAliases.map(mw.util.escapeRegExp).join('|'); // MASTER PROTECTION DEFINITIONS var PROTECTION_DEFS = [{ id: 'nowiki', isOn: true, label: 'Nowiki: <nowiki>', regex: /<nowiki>[\s\S]*?<\/nowiki>|<nowiki\s*\/>/gi }, { id: 'comments', isOn: true, label: 'Comments: <!' + '-- -->', regex: new RegExp('<!' + '--[\\s\\S]*?--' + '>', 'g') }, { id: 'headers', isOn: false, label: 'Headers: == Title ==', regex: /^==+[\s\S]+?==+\s*$/gm }, { id: 'templates', isOn: false, label: 'Templates: {{...}}', open: '{{', close: '}}', species: null, regex: null }, { id: 'tables', isOn: false, label: 'Tables: {|...|}', open: '\n{|', close: '\n|}', regex: null }, { id: 'images', isOn: false, label: 'Images: [[File:...|...|...]]', open: '[[', close: ']]', species: '(?:' + REGEX_FILE_PFX + ')\\s*:', regex: null }, { id: 'refs', isOn: true, label: 'Refs: <ref...', regex: /<ref[^>]*?\/>|<ref[^>]*?(?<!\/)>[\s\S]*?<\/ref>/gi }, { id: 'blocks', isOn: false, label: 'Blocks: math, gallery...', regex: null }, { id: 'categories', isOn: true, label: 'Categories: [[Category:...]]', regex: new RegExp('\\[\\[\\s*(' + REGEX_CAT_PFX + ')\\s*:[^\\]]+\\]\\]', 'giu') }, { id: 'files', isOn: true, label: 'File names: File:...', regex: new RegExp('(?<=\\[\\[\\s*:?(:?' + REGEX_FILE_PFX + ')\\s*:)[^|\\]]+' + '|^\\s*(?:' + REGEX_FILE_PFX + ')\\s*:([^\\][}{|\\n]{1,150}\\.(?:svg|png|jpe?g|gif|tiff|webp|xcf|mp3|midi|ogg|webm|flac|wav|mpe?g|pdf|djv))', 'gmiu') }, { id: 'targets', isOn: false, label: 'Targets of [[...|', regex: /(?<=\[\[:?)[^|\]]+?(?=\||\]\])/g }, { id: 'extlinks', isOn: true, label: 'External links: [...]', regex: /(?<=\[)(https?:\/\/|ftps?:\/\/|mailto:)[^\]]+(?=\])/gi }, { id: 'urls', isOn: true, label: 'URLs: http...', regex: /https?:\/\/[^\s<>[\]"'`()]+/gi } ]; // ===================================================================== // 2. CSS STYLES // ===================================================================== var styles = ` * { box-sizing: border-box; } #wa-root { font-family: sans-serif; height: 100vh; width: 100vw; overflow: hidden; display: flex; font-size: 14px; } #wa-left-panel { width: 400px; min-width: 400px; max-width: 400px; background: var(--background-color-base, #fff); border-right: 1px solid #c8ccd1; display: flex; flex-direction: column; z-index: 10; overflow-x: hidden; } #wa-left-panel h3 { color: #3f6fcf; text-align: center; margin: 12px 0 0 0; } #wa-username { color: #3f6fcf; text-align: center; margin: 2px 0; font-size: 92%; } #wa-content-area { flex: 1; padding: 10px 10px 100px 10px; overflow-y: auto; overflow-x: hidden; } #wa-right-panel { flex: 1; display: flex; flex-direction: column; height: 100%; background: var(--background-color-interactive, #eaecf0); overflow: hidden; } #wa-visual-output { flex: 0 0 45%; min-height: 0; overflow-y: auto; background: var(--background-color-base, #fff); padding: 20px; border-bottom: 1px solid #c8ccd1; } .wa-editor-header { flex: 0 0 40px; gap:4em; min-height: 40px; padding: 0 7px; background: var(--background-color-interactive-subtle, #f8f9fa); border-bottom: 1px solid #c8ccd1; color: var(--color-subtle, #54595d); display: flex; justify-content: space-between; align-items: center; white-space: nowrap; z-index: 10; } .wa-editor-header.wa-dirty { background: var(--background-color-warning-subtle, #fdf2d5); border-bottom: 1px solid #e6a700; } .wa-header-left { flex: 1; display: flex; align-items: center; overflow: hidden; } .wa-title-link { font-weight: bold; font-size: 1.1em; color: var(--color-progressive--focus, #36c) !important; text-decoration: none; text-overflow: ellipsis; overflow: hidden; max-width: 300px; } .wa-title-link:hover { text-decoration: underline; } .wa-header-sep { margin: 0 10px; border-right: 1px solid #ccc; height: 16px; display: inline-block; } .wa-unsaved-wrapper { display: none; align-items: center; } .wa-dirty .wa-unsaved-wrapper { display: inline-flex; } .wa-unsaved-dot { color: var(--color-destructive, #bf3c2c); font-size: 1.2em; margin-right: 5px; line-height: 1; } .wa-unsaved-text { color: var(--color-placeholder, #72777d); font-size: 0.9em; font-weight: normal; } .wa-header-center { flex: 0 0 auto; text-align: center; } .wa-status-label { font-weight: bold; font-size: 0.85em; color: var(--color-base, #202122); text-transform: uppercase; letter-spacing: 0.5px; } .wa-status-error { color: var(--color-error, #bf3c2c); } .wa-status-working { color: var(--color-progressive--focus, #36c); } .wa-header-right { flex: 1; text-align: right; font-size: 0.85em; color: var(--color-placeholder, #72777d); display: flex; justify-content: flex-end; align-items: center; gap: 8px; } .wa-info-container { margin-right: 10px; } .wa-tools-container { display: flex; align-items: center; gap: 2px; } .wa-resize-container { display: flex; flex-direction: column; justify-content: center; height: 100%; margin-left: 10px; padding-left: 5px; border-left: 1px solid #ccc; } .wa-resize-btn { cursor: pointer; color: #72777d; user-select: none; width: 20px; height: 14px; display: flex; align-items: center; justify-content: center; transition: color 0.1s ease-in-out; } .wa-resize-btn:hover { color: #36c; } .wa-resize-btn.wa-resize-disabled { color: #ccc; cursor: default; } #wa-proc-header { margin-top: 15px !important; border-bottom: none !important; cursor: default; } #wa-proc-title { font-weight: bold; padding: 10px; display: block; } #wa-proc-content { padding: 0 10px 15px 10px; } #wa-editor-area { flex: 1; min-height: 0; display: flex; flex-direction: column; background: var(--background-color-base, #fff); position: relative; overflow: hidden; } #wa-editor-textarea { flex: 1; height: 100%; font-family: monospace; font-size: 13px; border: none; outline: none; padding: 10px; resize: none; width: 100%; } .cm-editor { height: 100% !important; flex: 1; } .wa-section-header { margin-top: 12px; border-bottom: 1px solid #eee; width: 100%; display: block; margin-left: 0 !important; } #wa-content-area .wa-section-header:first-child, #wa-content-area .wa-section-header.oo-ui-buttonElement-frameless:first-child { margin-top: 0; margin-left: 0 !important; } .wa-section-header > .oo-ui-buttonElement-button { text-align: left; padding: 10px 10px !important; margin: 0 !important; display: block; width: 100%; position: relative; border-left: 3px solid #3f6fcf !important; border-radius: 3px !important; background-color: transparent !important; } .wa-section-header > .oo-ui-buttonElement-button:focus { outline: none !important; } .wa-section-header .oo-ui-labelElement-label { font-weight: bold; padding-left: 0 !important; margin-left: 0 !important; color: var(--color-base, #202122); } .wa-section-header .oo-ui-indicatorElement-indicator { position: absolute; right: 10px !important; top: 50%; margin-top: -10px; left: auto !important; width: 20px; } .wa-foldable-content { display: none; padding: 10px 0; } .wa-source-options { background: var(--background-color-interactive-subtle, #f8f9fa); border: 1px solid #c8ccd1; border-top: none; padding: 8px; margin-bottom: 10px; font-size: 0.9em; } .wa-opt-row { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 5px; } .wa-opt-label { font-weight: bold; width: 100%; margin-bottom: 5px; color: var(--color-base, #202122); } .wa-opt-row > div { margin-top: 8px !important; margin-bottom: 8px !important; } .wa-rule-row { background: var(--background-color-interactive-subtle, #f8f9fa); border: 1px solid #c8ccd1; padding: 8px; margin-bottom: 8px; border-radius: 4px; display: flex; align-items: stretch; transition: background-color 0.3s; } .wa-rule-row.wa-highlight { background-color: var(--background-color-interactive, #eaecf0); border-color: #36c; } .wa-rule-controls { display: flex; flex-direction: column; justify-content: center; gap: 0px; padding-right: 4px; border-right: 1px solid #eee; margin-right: 8px; } .wa-rule-btn { margin: 0 !important; margin-right: 0 !important; margin-left: 0 !important; } .wa-rule-btn > .oo-ui-buttonElement-button { margin: 0 !important; } .wa-rule-content { flex: 1; min-width: 0; } .wa-rule-opt-row { display: flex; justify-content: space-between; align-items: center; margin-top: 5px; } #wa-ns-selector { width: 100%; margin-bottom: 10px; font-family: sans-serif; font-size: 0.9em; border: 1px solid #a2a9b1; } .wa-lib-dialog > .oo-ui-window-frame { width: 80vw !important; max-width: none !important; height: 80vh !important; max-height: none !important; } .wa-lib-editorwrapper { height: 100%; border: 1px solid #c8ccd1; position: relative; boxSizing: border-box; } .wa-page-list-raw textarea { font-family: monospace; font-size: 0.9em; white-space: pre; overflow-x: auto; } .wa-list-running textarea { background-color: var(--background-color-neutral-subtle, #f8f8f8) !important; color: var(--color-base, #202122) !important; } .wa-grid-container { display: flex; gap: 6px; margin-bottom: 10px; } .wa-grid-col { flex: 1; display: flex; flex-direction: column; gap: 6px; } .wa-grid-col .oo-ui-buttonWidget { width: 100%; } .wa-grid-col .oo-ui-buttonWidget .oo-ui-buttonElement-button { width: 100%; text-align: center; justify-content: center; } .wa-toolbar { display: flex; justify-content: flex-end; align-items: center; gap: 4px; border-bottom: 1px solid #eee; padding-bottom: 4px; margin-bottom: 4px; } .wa-list-counter { margin-right: auto; font-weight: bold; color: var(--color-subtle, #54595d); font-size: 0.9em; padding-left: 5px; } .wa-project-bar { display: flex; flex-wrap: wrap; gap: 8px; padding: 0 10px; margin: 8px 0; justify-content: center; } .wa-project-bar .oo-ui-buttonElement-button { padding-left: 36px !important; padding-right: 12px !important; font-size: 0.9em; } .wa-project-bar .oo-ui-iconElement-icon { left: 10px !important; } .wa-settings-header { font-weight: bold; color: var(--color-subtle, #54595d); margin-bottom: 8px; display: block; text-transform: uppercase; font-size: 0.85em; } .wa-setting-row { display: flex; align-items: center; margin-bottom: 6px; } .wa-bot-row { background: var(--background-color-success-subtle, #dff2eb); border: 1px solid #a5d6a7; padding: 8px; margin-bottom: 10px; border-radius: 4px; display: flex; align-items: center; justify-content: flex-start; gap: 15px; } table.diff { width: 100%; font-family: "Adwaita Mono", "Courier New", monospace } table.diff td { vertical-align: top; } table.diff tr:hover td { background-color: var(--background-color-progressive-subtle--hover, #d9e2ff); cursor: pointer; } @keyframes wa-pulse-red { 0% { box-shadow: 0 0 0 0 rgba(255, 0, 0, 0.4); border-color: #ff0000; } 70% { box-shadow: 0 0 0 6px rgba(255, 0, 0, 0); border-color: #ff0000; } 100% { box-shadow: 0 0 0 0 rgba(255, 0, 0, 0); border-color: #ff0000; } } .wa-summary-warning input { animation: wa-pulse-red 1s infinite; border-color: #ff0000 !important; } `; $('<style>').text(styles).appendTo('head'); $('body').empty(); // ===================================================================== // 3. HELPER FUNCTIONS // ===================================================================== function checkPermissions() { return new Promise(function(resolve) { var api = new mw.Api(); var projectNs = mw.config.get('wgFormattedNamespaces')[4]; var checkTitles = { 'permissions': projectNs + ':AutoWikiBrowser/CheckPageJSON', 'tag': 'MediaWiki:Tag-wAwB' }; api.get({ action: 'query', prop: 'revisions', titles: Object.values(checkTitles).join('|'), rvprop: 'content', rvslots: 'main', formatversion: 2 }).then(function(data) { var pagePerms = data.query.pages.find(p => p.title === checkTitles['permissions']); var pageTag = data.query.pages.find(p => p.title === checkTitles['tag']); DO_TAG = pageTag.missing === undefined; var userName = mw.config.get('wgUserName'); var userGroups = mw.config.get('wgUserGroups'); var isSysop = userGroups.includes('sysop'); if (!pagePerms.missing) { try { var content = pagePerms.revisions[0].slots.main.content; var json = JSON.parse(content); var inEnabledUsers = json.enabledusers && json.enabledusers.includes(userName); var inEnabledBots = json.enabledbots && json.enabledbots.includes(userName); var isBotGroup = userGroups.includes('bot'); var canSave = inEnabledUsers || inEnabledBots || isSysop; var allowBot = inEnabledBots && isBotGroup; resolve({ canSave: canSave, allowBot: allowBot, saveDelay: 0 }); } catch (e) { resolve({ canSave: false, allowBot: false, saveDelay: 0 }); } } else { var editCount = mw.config.get('wgUserEditCount'); if (editCount > 500) resolve({ canSave: true, allowBot: false, saveDelay: 20000 }); else resolve({ canSave: false, allowBot: false, saveDelay: 0 }); } }).catch(function() { resolve({ canSave: false, allowBot: false, saveDelay: 0 }); }); }); } function getUserCode(widget, globalName) { var val = widget.getValue().trim(); if (!val || val.startsWith('// Enter')) { if (window[globalName] && typeof window[globalName] === 'function') { var s = window[globalName].toString(); return s.substring(s.indexOf('{') + 1, s.lastIndexOf('}')); } return ""; } if (val.startsWith('function')) { return val.substring(val.indexOf('{') + 1, val.lastIndexOf('}')); } return val; } function normalizeLine(line) { if (!line) return null; // Pass through comments/STOP commands (trimmed) if (line.trim().startsWith('####')) return line.trim(); // Handle Title|Variables var parts = line.split('|'); var title = parts[0].trim(); if (!title) return null; // Skip if title is empty // Reassemble: Clean Title + Original Variables (preserving whitespace) var rest = parts.length > 1 ? parts.slice(1).join('|') : null; return title + (rest !== null ? '|' + rest : ''); } function getNormalizedList(text) { if (!text) return []; return text.split('\n') .map(normalizeLine) .filter(function(l) { return l !== null; }); } function getDeduplicatedList(text) { if (!text) return []; var seen = new Set(); var out = []; var lines = text.split('\n'); for (var i = 0; i < lines.length; i++) { var clean = normalizeLine(lines[i]); if (clean && !seen.has(clean)) { seen.add(clean); out.push(clean); } } return out; } function parseTypoContent(content) { if (!content) return []; try { var $wrapper = $('<body>').html(content); var rules = []; $wrapper.find('Typo:not([disabled])').each(function() { var $t = $(this); var find = $t.attr('find'); var replace = $t.attr('replace'); if (find && replace !== undefined) { rules.push({ find: find, replace: replace, regex: true, flags: 'gmu', enabled: true, isFunc: false }); } }); return rules; } catch (e) { return []; } } // ===================================================================== // 4. UI CONSTRUCTION // ===================================================================== checkPermissions().then(function(pState) { PERMS = pState; var $main = $('<div>').attr('id', 'wa-root').appendTo('body'); var $left = $('<div>').attr('id', 'wa-left-panel').appendTo($main); $left.append($('<h3>').append($('<a>').attr('href', DOC_URL).attr('target', '_blank').text(APP_NAME).css({ 'text-decoration': 'none', 'color': 'inherit' }))); $left.append($('<div>').attr('id', 'wa-username').append($('<a>').attr('href', mw.util.getUrl('Special:Contributions/' + mw.config.get('wgUserName'))).attr('target', '_blank').text('User: ' + mw.config.get('wgUserName')).css({ 'text-decoration': 'none', 'color': 'inherit' }))); var btnSaveProj = new OO.ui.ButtonWidget({ icon: 'download', label: 'Save project', framed: false, flags: 'progressive' }); var btnLoadProj = new OO.ui.ButtonWidget({ icon: 'upload', label: 'Load project', framed: false }); var $projBar = $('<div>').addClass('wa-project-bar').append(btnSaveProj.$element, btnLoadProj.$element); $left.append($projBar); var $fileInput = $('<input type="file" accept=".json">').hide().appendTo('body'); var $content = $('<div>').attr('id', 'wa-content-area').appendTo($left); var $right = $('<div>').attr('id', 'wa-right-panel').appendTo($main); var $editorHeader = $('<div>').addClass('wa-editor-header').appendTo($right); var $headerLeft = $('<div>').addClass('wa-header-left').appendTo($editorHeader); var $titleLink = $('<a>').addClass('wa-title-link').text('Page content').attr('target', '_blank').appendTo($headerLeft); $('<span>').addClass('wa-header-sep').appendTo($headerLeft); var $unsavedWrapper = $('<span>').addClass('wa-unsaved-wrapper').appendTo($headerLeft); $('<span>').addClass('wa-unsaved-dot').text('●').appendTo($unsavedWrapper); $('<span>').addClass('wa-unsaved-text').text('Unsaved').appendTo($unsavedWrapper); var $headerCenter = $('<div>').addClass('wa-header-center').appendTo($editorHeader); var $statusLabel = $('<span>').addClass('wa-status-label').text('READY').appendTo($headerCenter); var $headerRight = $('<div>').addClass('wa-header-right').appendTo($editorHeader); var $infoContainer = $('<span>').addClass('wa-info-container').appendTo($headerRight); var $toolsContainer = $('<div>').addClass('wa-tools-container').appendTo($headerRight); var $resizeContainer = $('<div>').addClass('wa-resize-container').appendTo($headerRight); var $adminTools = $('<div>').addClass('wa-admin-tools').hide().appendTo($toolsContainer); // Wide chevron SVGs var svgUp = '<svg xmlns="http://www.w3.org/2000/svg" width="14" height="8" viewBox="0 0 24 12"><path d="M2 10 L12 2 L22 10" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/></svg>'; var svgDown = '<svg xmlns="http://www.w3.org/2000/svg" width="14" height="8" viewBox="0 0 24 12"><path d="M2 2 L12 10 L22 2" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/></svg>'; var $btnSizeUp = $('<div>').addClass('wa-resize-btn').html(svgUp).attr('title', 'Decrease view size'); var $btnSizeDown = $('<div>').addClass('wa-resize-btn').html(svgDown).attr('title', 'Increase view size'); $resizeContainer.append($btnSizeUp, $btnSizeDown); function setPanelHeight(modeIndex) { currentHeightMode = modeIndex; if (currentHeightMode < 0) currentHeightMode = 0; if (currentHeightMode > 2) currentHeightMode = 2; $('#wa-visual-output').css('flex-basis', heightValues[currentHeightMode]); $btnSizeUp.toggleClass('wa-resize-disabled', currentHeightMode === 0); $btnSizeDown.toggleClass('wa-resize-disabled', currentHeightMode === 2); } $btnSizeUp.on('click', function() { if (!$(this).hasClass('wa-resize-disabled')) setPanelHeight(currentHeightMode - 1); }); $btnSizeDown.on('click', function() { if (!$(this).hasClass('wa-resize-disabled')) setPanelHeight(currentHeightMode + 1); }); setPanelHeight(1); if (CAN_MOVE) { var btnAdminMove = new OO.ui.ButtonWidget({ icon: 'move', title: 'Move page to $xA', disabled: true, framed: false }); $adminTools.append(btnAdminMove.$element).show(); } if (IS_ADMIN) { var btnAdminDel = new OO.ui.ButtonWidget({ icon: 'trash', title: 'Delete page', disabled: true, framed: false }); var btnAdminProt = new OO.ui.ButtonWidget({ icon: 'lock', title: 'Protect page', disabled: true, framed: false }); $adminTools.append(btnAdminDel.$element, btnAdminProt.$element).show(); } var btnWatch = new OO.ui.ButtonWidget({ icon: 'star', title: 'Watch this page', framed: false, disabled: true, accessKey: 'w' }); $toolsContainer.append(btnWatch.$element); var $visualOut = $('<div>').attr('id', 'wa-visual-output').html('<div style="color:#aaa; text-align:center; margin-top:50px;">Ready to start...</div>').prependTo($right); var $editorArea = $('<div>').attr('id', 'wa-editor-area').appendTo($right); var $textArea = $('<textarea>').attr('id', 'wa-editor-textarea').attr('placeholder', 'Page text will appear here...').appendTo($editorArea); function setStatus(msg, type) { if (!msg) msg = "Ready"; $statusLabel.text(msg).removeClass('wa-status-error wa-status-working'); if (type === 'error') $statusLabel.addClass('wa-status-error'); if (type === 'working') $statusLabel.addClass('wa-status-working'); } // EDITOR OBJECT var Editor = { mode: 'textarea', cmInstance: null, init: function() { var self = this; mw.loader.using(['ext.CodeMirror', 'ext.CodeMirror.mode.mediawiki']).then(function(require) { try { self.cmInstance = new(require('ext.CodeMirror'))($textArea[0], (require('ext.CodeMirror.mode.mediawiki')).mediawiki()); self.cmInstance.initialize(); self.mode = 'codemirror'; } catch (e) { console.error("CM Error", e); } }).catch(function(err) { console.error("CM Load Error:", err); }); $textArea.on('input', updateDirtyState); }, getValue: function() { return (this.mode === 'codemirror' && this.cmInstance) ? this.cmInstance.view.state.doc.toString() : $textArea.val(); }, setValue: function(text) { $textArea.val(text); if (this.mode === 'codemirror' && this.cmInstance) { this.cmInstance.view.dispatch({ changes: { from: 0, to: this.cmInstance.view.state.doc.length, insert: text } }); } else { $textArea[0].dispatchEvent(new Event('input')); } }, setDisabled: function(d) { $textArea.prop('disabled', d); if (this.mode === 'codemirror' && this.cmInstance) { this.cmInstance.view.contentDOM.contentEditable = !d; $($textArea).parent().find('.cm-editor').css('opacity', d ? 0.5 : 1); } }, scrollToLine: function(n) { if (isNaN(n)) return; if (this.mode === 'codemirror' && this.cmInstance) { var v = this.cmInstance.view; var l = v.state.doc.line(n); v.dispatch({ effects: v.constructor.scrollIntoView(l.from, { y: 'center' }), selection: { anchor: l.from } }); v.focus(); } } }; var WorkerEngine = { activeWorker: null, workerURL: null, currentLibCode: null, timeoutTimer: null, initWorker: function(libCode) { this.destroy(); // Clean up existing if any this.currentLibCode = libCode || ""; var scriptContent = this.currentLibCode + "\n\n" + ` self.onmessage = async function(e) { try { var data = e.data; var inputs = data.texts || [data.text]; var vars = data.vars; var outputs = []; // Helper to construct async functions dynamically var AsyncFunction = Object.getPrototypeOf(async function(){}).constructor; function inject(str) { if (!str) return ""; return str.replace(/\\$x([A-Z]|x)/g, function(m) { return vars[m] || ""; }); } // Returns a Promise and handles 'await' inside user code async function execUserFunc(code, currentText, currentVars, sharedObj) { if (!code || code.trim() === "") return currentText; try { var func = new AsyncFunction('text', 'vars', 'shared', code); var res = await func(currentText, currentVars, sharedObj); if (res && typeof res === 'object' && res.skip) { return { _skipSignal: true, reason: res.reason || 'Script-requested skip' }; } return (res !== undefined) ? res : currentText; } catch (err) { throw err; // or: return currentText } } for (var i = 0; i < inputs.length; i++) { var text = inputs[i]; var shared = {}; // Shared context for this page // 1. Pre-Process var preRes; if (data.preCode && data.preCode.trim() !== "") { preRes = await execUserFunc(data.preCode, text, vars, shared); } else if (typeof wAwB_Pre === 'function') { try { preRes = await wAwB_Pre(text, vars, shared); if (preRes && typeof preRes === 'object' && preRes.skip) { preRes = { _skipSignal: true, reason: preRes.reason || 'Script-requested skip' }; } } catch (err) { preRes = text; } } else { preRes = text; } if (preRes && preRes._skipSignal) { self.postMessage({ skipped: true, reason: preRes.reason }); return; } text = (preRes !== undefined) ? preRes : text; // 2. Rules Processing if (data.rules && data.rules.length > 0) { data.rules.forEach(function(rule) { var findStr = inject(rule.find); if (!findStr) return; if (rule.isFunc) { try { var userFunc = new Function('match', 'groups', 'vars', 'shared', rule.replace); text = text.replace(new RegExp(findStr, (rule.flags || 'gmu').replace(/[^gimsuvy]/g, '')), function(...args) { var match = args[0]; var groups = args.slice(1, -2); try { var res = userFunc(match, groups, vars, shared); return res !== undefined ? res : match; } catch (err) { return match; } }); } catch (e) {} } else { var repStr = inject(rule.replace).replace(/\\\\n/g, "\\n").replace(/\\\\t/g, "\\t").replace(/\\\\r/g, "\\r"); if (rule.regex) { try { var flags = (rule.flags || 'gmu').replace(/[^gimsuvy]/g, ''); text = text.replace(new RegExp(findStr, flags), repStr); } catch (e) {} } else { var finalFind = findStr.replace(/\\\\n/g, "\\n").replace(/\\\\t/g, "\\t").replace(/\\\\r/g, "\\r"); text = text.split(finalFind).join(repStr); } } }); } // 3. Post-Process var postRes; if (data.postCode && data.postCode.trim() !== "") { postRes = await execUserFunc(data.postCode, text, vars, shared); } else if (typeof wAwB_Post === 'function') { try { postRes = await wAwB_Post(text, vars, shared); if (postRes && typeof postRes === 'object' && postRes.skip) { postRes = { _skipSignal: true, reason: postRes.reason || 'Script-requested skip' }; } } catch (err) { postRes = text; } } else { postRes = text; } if (postRes && postRes._skipSignal) { self.postMessage({ skipped: true, reason: postRes.reason }); return; } text = (postRes !== undefined) ? postRes : text; outputs.push(text); } self.postMessage({ success: true, texts: outputs }); } catch (err) { self.postMessage({ success: false, error: err.toString() }); } }; `; var blob = new Blob([scriptContent], { type: 'application/javascript' }); this.workerURL = URL.createObjectURL(blob); this.activeWorker = new Worker(this.workerURL); }, run: function(payload) { var self = this; return new Promise(function(resolve, reject) { // Re-init if no worker exists, or if the user changed the library code if (!self.activeWorker || self.currentLibCode !== (payload.libraryCode || "")) { self.initWorker(payload.libraryCode); } if (self.timeoutTimer) clearTimeout(self.timeoutTimer); self.timeoutTimer = setTimeout(function() { self.destroy(); // Assassinate the stuck worker reject("Script timed out (" + SCRIPT_TIMEOUT_MS + "ms)."); }, SCRIPT_TIMEOUT_MS); self.activeWorker.onmessage = function(e) { clearTimeout(self.timeoutTimer); if (e.data.skipped) resolve({ skipped: true, reason: e.data.reason }); else if (e.data.success) resolve({ success: true, texts: e.data.texts }); else reject(e.data.error); }; self.activeWorker.postMessage(payload); }); }, destroy: function() { if (this.activeWorker) { this.activeWorker.terminate(); this.activeWorker = null; } if (this.workerURL) { URL.revokeObjectURL(this.workerURL); this.workerURL = null; } if (this.timeoutTimer) { clearTimeout(this.timeoutTimer); this.timeoutTimer = null; } } }; var PageProtector = { store: [], getKey: function() { var id = this.store.length.toString(); var p = ""; for (var i = 0; i < id.length; i++) { p += String.fromCharCode(0xE010 + parseInt(id[i])); } return '\uE000' + p + '\uE001'; }, protect: function(text, mode, config, templateSpecies = null) { this.store = []; var self = this; var safeRep = function(t, r) { return t.replace(r, function(m) { if (!m) return m; var key = self.getKey(); self.store.push(m); return key; }); }; var shouldProcess = function(id) { if (mode === 'target') return config === id; return config[id] === true; }; var matchedBrackets = function(text, op, cl, species = '') { var newText = "", depth = 0, start = 0, cursor = 0; var speciesRegex = species ? new RegExp(species, 'iu') : null; for (var i = 0; i < text.length; i++) { if (text[i] === op[0] && text.slice(i, i + op.length) === op) { if (depth === 0) start = i; depth++; i += op.length - 1; } else if (text[i] === cl[0] && text.slice(i, i + cl.length) === cl) { if (depth > 0) { depth--; if (depth === 0) { var chunk = text.substring(start, i + cl.length); if (!speciesRegex || speciesRegex.test(chunk)) { var key = self.getKey(); self.store.push(chunk); newText += text.substring(cursor, start) + key; } else { newText += text.substring(cursor, i + cl.length); } cursor = i + cl.length; } i += cl.length - 1; } } } newText += text.substring(cursor); return newText; }; PROTECTION_DEFS.forEach(function(def) { if (shouldProcess(def.id)) { if (def.id === 'blocks') { ['math', 'pre', 'source', 'syntaxhighlight', 'code', 'gallery'].forEach(t => text = safeRep(text, new RegExp('<' + t + '[^>]*?>[\\s\\S]*?<\\/' + t + '>|<' + t + '[^>]*?/>', 'gi'))); } else if (['templates', 'tables', 'images'].includes(def.id)) { var activeSpecies = (def.id === 'templates') ? templateSpecies : def.species; text = matchedBrackets(text, def.open, def.close, activeSpecies || ''); } else if (def.regex) { text = safeRep(text, def.regex); } } }); return text; }, restore: function(text) { var self = this; var loop = 100; while (/(\uE000[\uE010-\uE019]+\uE001)/.test(text) && loop > 0) { text = text.replace(/\uE000([\uE010-\uE019]+)\uE001/g, function(m, d) { var id = ""; for (var i = 0; i < d.length; i++) id += (d.charCodeAt(i) - 0xE010).toString(); return self.store[parseInt(id, 10)] || m; }); loop--; } return text; } }; var accordionRegistry = []; function addSection(title, $inner) { var btn = new OO.ui.ButtonWidget({ label: title, indicator: 'down', framed: false, classes: ['wa-section-header'] }); var box = $('<div>').addClass('wa-foldable-content').append($inner); var sectionObj = { btn: btn, box: box, label: title }; accordionRegistry.push(sectionObj); btn.on('click', function() { var isOpening = !box.is(':visible'); if (isOpening) { accordionRegistry.forEach(function(sec) { if (sec !== sectionObj) { sec.box.hide(); sec.btn.setIndicator('down'); } }); } box.toggle(); btn.setIndicator(box.is(':visible') ? 'up' : 'down'); }); $content.append(btn.$element, box); return sectionObj; } // WIDGETS var srcSelect = new OO.ui.DropdownInputWidget({ options: [{ data: 'cat', label: 'Category' }, { data: 'linksto', label: 'Pages linking to...' }, { data: 'linkson', label: 'Links on page...' }, { data: 'prefix', label: 'Pages with prefix...' }, { data: 'watchlist', label: 'Watchlist' }, { data: 'search', label: 'Wiki search' }, { data: 'usercontribs', label: 'User contributions' }, { data: 'pageswithprop', label: 'Pages with property' }] }); var srcInput = new OO.ui.TextInputWidget({ placeholder: 'Category...' }); var now = new Date(); var today = now.toISOString().split('T')[0]; var srcInputUser = new OO.ui.TextInputWidget({ placeholder: 'Username' }); var srcInputStartDate = new OO.ui.TextInputWidget({ value: today + 'T00:00:00', placeholder: 'ISO start date' }); var srcInputEndDate = new OO.ui.TextInputWidget({ value: today + 'T23:59:59', placeholder: 'ISO end date' }); var srcDropProp = new OO.ui.DropdownInputWidget({ options: [] }); var $optContainer = $('<div>').addClass('wa-source-options').hide(); var $optCat = $('<div>').hide(); var $optUser = $('<div>').hide(); var $optProp = $('<div>').hide(); var chkCatPages = new OO.ui.CheckboxInputWidget({ selected: true }); var chkCatSub = new OO.ui.CheckboxInputWidget({ selected: false }); var chkCatFile = new OO.ui.CheckboxInputWidget({ selected: false }); $optCat.append($('<div>').addClass('wa-opt-label').text('Include:'), new OO.ui.FieldLayout(chkCatPages, { label: 'Pages', align: 'inline' }).$element, new OO.ui.FieldLayout(chkCatSub, { label: 'Subcats', align: 'inline' }).$element, new OO.ui.FieldLayout(chkCatFile, { label: 'Files', align: 'inline' }).$element); $optUser.append(new OO.ui.FieldLayout(srcInputUser, { label: 'User', align: 'top' }).$element, new OO.ui.FieldLayout(srcInputStartDate, { label: 'Start (Older)', align: 'top' }).$element, new OO.ui.FieldLayout(srcInputEndDate, { label: 'End (Newer)', align: 'top' }).$element); $optProp.append(new OO.ui.FieldLayout(srcDropProp, { label: 'Property', align: 'top' }).$element); var $optLinks = $('<div>').hide(); var chkLinkWiki = new OO.ui.CheckboxInputWidget({ selected: true }); var chkLinkTrans = new OO.ui.CheckboxInputWidget({ selected: false }); var chkLinkImg = new OO.ui.CheckboxInputWidget({ selected: false }); var dropLinkRedir = new OO.ui.DropdownInputWidget({ options: [{ data: 'nonredirects', label: 'No redirects' }, { data: 'all', label: 'Both' }, { data: 'redirects', label: 'Redirects only' }] }); var chkLinkToRedir = new OO.ui.CheckboxInputWidget({ selected: false }); $optLinks.append($('<div>').addClass('wa-opt-label').text('What to include:'), $('<div>').addClass('wa-opt-row').append(new OO.ui.FieldLayout(chkLinkWiki, { label: 'Wikilinks', align: 'inline' }).$element, new OO.ui.FieldLayout(chkLinkTrans, { label: 'Transclusions', align: 'inline' }).$element, new OO.ui.FieldLayout(chkLinkImg, { label: 'File usage', align: 'inline' }).$element), $('<div>').addClass('wa-opt-label').text('Redirects:'), dropLinkRedir.$element, new OO.ui.FieldLayout(chkLinkToRedir, { label: 'Include links to redirects', align: 'inline' }).$element); $optContainer.append($optCat, $optLinks, $optUser, $optProp); var queryCache = {}; var lastMode = 'cat'; srcSelect.on('change', function(newMode) { if (!isLoadingProject) { if (lastMode !== 'watchlist' && lastMode !== 'usercontribs' && lastMode !== 'pageswithprop') { queryCache[lastMode] = srcInput.getValue(); } } $optContainer.hide(); $optCat.hide(); $optLinks.hide(); $optUser.hide(); $optProp.hide(); srcInput.setDisabled(false).$element.show(); if (newMode === 'cat') { $optContainer.show(); $optCat.show(); } else if (newMode === 'linksto') { $optContainer.show(); $optLinks.show(); } else if (newMode === 'usercontribs') { $optContainer.show(); $optUser.show(); srcInput.setDisabled(true).$element.hide(); } else if (newMode === 'pageswithprop') { $optContainer.show(); $optProp.show(); srcInput.setDisabled(true).$element.hide(); if (!propNamesLoaded) { new mw.Api().get({ action: 'query', list: 'pagepropnames', ppnlimit: 'max' }).then(function(d) { if (d.query && d.query.pagepropnames) { srcDropProp.setOptions(d.query.pagepropnames.map(p => ({ data: p.propname, label: p.propname }))); propNamesLoaded = true; } }); } } if (newMode === 'watchlist') { srcInput.setValue(''); srcInput.setDisabled(true); srcInput.$input.attr('placeholder', '(No query needed)'); } else if (newMode !== 'usercontribs' && newMode !== 'pageswithprop') { srcInput.setValue(queryCache[newMode] || ''); var ph = 'Query...'; if (newMode === 'cat') ph = 'Category name'; if (newMode === 'search') ph = 'Search query...'; if (newMode === 'prefix') ph = 'Page prefix...'; if (newMode === 'linksto') ph = 'Pages linking to this title...'; if (newMode === 'linkson') ph = 'Get links from this page...'; srcInput.$input.attr('placeholder', ph); } lastMode = newMode; }); srcSelect.emit('change', srcSelect.getValue()); var $nsSelect = $('<select>').attr('id', 'wa-ns-selector').attr('multiple', 'multiple').attr('size', '8'); var nsMap = mw.config.get('wgFormattedNamespaces'); for (var id in nsMap) { if (parseInt(id) >= 0) $nsSelect.append($('<option>').val(id).text(id + ': ' + (nsMap[id] || '(Main)'))); } $nsSelect.val(['0']); var btnAdd = new OO.ui.ButtonWidget({ label: 'Add to list', icon: 'add', flags: ['primary', 'progressive'] }); var $btnRow = $('<div>').css({ 'display': 'flex', 'justify-content': 'flex-end', 'margin-top': '10px' }); var $fetchStatus = $('<span>').css({ 'margin-right': '10px', 'color': '#888', 'font-size': '0.85em', 'align-self': 'center' }).hide(); $btnRow.append($fetchStatus, btnAdd.$element); addSection('Source', $('<div>').append(new OO.ui.FieldLayout(srcSelect, { label: 'Mode', align: 'top' }).$element, new OO.ui.FieldLayout(srcInput, { label: 'Query', align: 'top' }).$element, $optContainer, $('<div>').text('Namespaces:').css({ 'font-weight': 'bold', 'margin-top': '5px' }), $nsSelect, $btnRow)); var redirMode = new OO.ui.RadioSelectWidget({ items: [new OO.ui.RadioOptionWidget({ data: 'edit', label: 'Edit the redirect page (Default)' }), new OO.ui.RadioOptionWidget({ data: 'follow', label: 'Follow redirect (Edit target)' }), new OO.ui.RadioOptionWidget({ data: 'skip', label: 'Skip redirects' })] }); redirMode.selectItemByData('edit'); var radSkipExist = new OO.ui.RadioSelectWidget({ items: [new OO.ui.RadioOptionWidget({ data: 'none', label: 'Process all' }), new OO.ui.RadioOptionWidget({ data: 'missing', label: 'Skip if page does not exist' }), new OO.ui.RadioOptionWidget({ data: 'exists', label: 'Skip if page exists' })] }); radSkipExist.selectItemByData('none'); var chkSkipNoChange = new OO.ui.CheckboxInputWidget({ selected: false }); var inpSkipContains = new OO.ui.TextInputWidget({ placeholder: 'Text/Regex for Skip if FOUND' }); var togSkipContainsRegex = new OO.ui.ToggleSwitchWidget({ value: false, title: 'Use regex' }); var inpSkipNotContains = new OO.ui.TextInputWidget({ placeholder: 'Text/Regex for Skip if MISSING' }); var togSkipNotContainsRegex = new OO.ui.ToggleSwitchWidget({ value: false, title: 'Use regex' }); var inpSkipCategories = new OO.ui.TextInputWidget({ placeholder: 'Skip if in: Category1|Category2' }); var inpSkipNotCategories = new OO.ui.TextInputWidget({ placeholder: 'Skip if NOT in: Category1|Category2' }); var $settingsPanel = $('<div>') .append($('<span>').addClass('wa-settings-header').text('Redirects')) .append(redirMode.$element) .append($('<hr>').css('border-top', '1px solid #eee')) .append($('<span>').addClass('wa-settings-header').text('Skip logic')) .append(new OO.ui.FieldLayout(chkSkipNoChange, { label: 'Skip if no changes made', align: 'inline' }).$element.css('margin-bottom', '8px')) .append(radSkipExist.$element) .append($('<hr>').css('border-top', '1px solid #eee')) .append($('<span>').addClass('wa-settings-header').text('Content filters')) .append($('<div>').addClass('wa-setting-row').append(inpSkipContains.$element.css('flex', 1), togSkipContainsRegex.$element.css('margin-left', '5px'))) .append($('<div>').addClass('wa-setting-row').append(inpSkipNotContains.$element.css('flex', 1), togSkipNotContainsRegex.$element.css('margin-left', '5px'))) .append($('<hr>').css('border-top', '1px solid #eee')) .append($('<span>').addClass('wa-settings-header').text('Category filters')) .append(new OO.ui.FieldLayout(inpSkipCategories, { label: 'Blacklist', align: 'top' }).$element) .append(new OO.ui.FieldLayout(inpSkipNotCategories, { label: 'Whitelist', align: 'top' }).$element); addSection('Skip', $settingsPanel); var dropProtMode = new OO.ui.DropdownInputWidget({ options: [{ data: 'protect', label: 'Protect (Exclude)' }, { data: 'target', label: 'Target (Edit Matches Only)' }] }); var inpTemplateFilter = new OO.ui.TextInputWidget({ placeholder: 'Regex: infobox rail line|railway' }); var $templateFilterLayout = new OO.ui.FieldLayout(inpTemplateFilter, { label: 'Template filter', align: 'top' }); var $protList = $('<div>'); var protCheckboxes = {}; PROTECTION_DEFS.forEach(function(def) { var chk = new OO.ui.CheckboxInputWidget({ selected: def.isOn }); protCheckboxes[def.id] = chk; $protList.append(new OO.ui.FieldLayout(chk, { label: def.label, align: 'inline' }).$element); }); var targetRadioItems = PROTECTION_DEFS.map(function(def) { return new OO.ui.RadioOptionWidget({ data: def.id, label: def.label }); }); var radTargetSet = new OO.ui.RadioSelectWidget({ items: targetRadioItems }); var $targetList = $('<div>').hide().append(radTargetSet.$element); dropProtMode.on('change', function(mode) { if (mode === 'protect') { $protList.show(); $targetList.hide(); } else { $protList.hide(); $targetList.show(); } }); addSection('Protection', $('<div>').addClass('wa-source-options') .append(new OO.ui.FieldLayout(dropProtMode, { label: 'Mode', align: 'top' }).$element) .append($('<hr>').css('border-top', '1px solid #eee')) .append($protList).append($targetList) .append($('<div style="margin-top:10px;">').append($templateFilterLayout.$element)) ); var $rulesList = $('<div>'); var btnAddRule = new OO.ui.ButtonWidget({ label: 'Add rule', icon: 'add' }); var rulesRegistry = []; addSection('Rules', $('<div>').append($rulesList, btnAddRule.$element)); var togWikiTypos = new OO.ui.ToggleSwitchWidget({ value: false }); var lblWikiStatus = $('<div>').css({ 'font-size': '0.85em', 'color': '#888', 'margin-top': '2px' }); var btnLoadLocal = new OO.ui.ButtonWidget({ icon: 'upload', label: 'Load file', framed: false }); var btnClearLocal = new OO.ui.ButtonWidget({ icon: 'trash', title: 'Clear local', framed: false, flags: 'destructive', disabled: true }); var lblLocalStatus = $('<div>').text('No local rules').css({ 'font-size': '0.85em', 'color': '#888', 'margin-top': '2px' }); var $typoInput = $('<input type="file">').hide().appendTo('body'); var $extRulesPanel = $('<div>').addClass('wa-source-options'); $extRulesPanel.append( $('<div>').css({ 'display': 'flex', 'align-items': 'center', 'justify-content': 'space-between' }).append($('<span>').text('Project:AutoWikiBrowser/Typos').css('font-weight', 'bold'), togWikiTypos.$element), $('<div>').css('margin-bottom', '10px').append(lblWikiStatus), $('<hr>').css('border-top', '1px solid #eee'), $('<div>').append($('<div>').css({ 'display': 'flex', 'align-items': 'center' }).append($('<span>').text('Local rules (session only)').css({ 'font-weight': 'bold' }), $('<div>').css('flex', '1'), btnLoadLocal.$element, btnClearLocal.$element), lblLocalStatus) ); addSection('External rules', $extRulesPanel); var txtPreScript = new OO.ui.MultilineTextInputWidget({ rows: 6, value: '', placeholder: '// Enter JavaScript function body here.\n// Available variables: text, vars, shared\nreturn text;' }); var txtPostScript = new OO.ui.MultilineTextInputWidget({ rows: 6, value: '', placeholder: '// Enter JavaScript function body here.\n// Available variables: text, vars, shared\nreturn text;' }); var btnLoadLib = new OO.ui.ButtonWidget({ icon: 'upload', title: 'Load library (.js)', framed: false }); var btnRemoveLib = new OO.ui.ButtonWidget({ icon: 'trash', title: 'Remove library', framed: false, flags: 'destructive' }); var txtLibStatus = new OO.ui.TextInputWidget({ value: '(No library loaded)', readOnly: true }); var $libInput = $('<input type="file" accept=".js">').hide().appendTo('body'); var btnEditLib = new OO.ui.ButtonWidget({ icon: 'edit', label: 'Edit project library', framed: false }); var $scriptPanel = $('<div>').append( $('<div>').css({ 'display': 'flex', 'align-items': 'center', 'gap': '5px', 'margin-bottom': '10px' }).append($('<span>').text('JS library:').css({ 'font-weight': 'bold', 'white-space': 'nowrap' }), txtLibStatus.$element.css('flex', '1'), btnLoadLib.$element, btnRemoveLib.$element), $('<div>').css({ 'display': 'flex', 'justify-content': 'flex-end', 'margin-bottom': '10px' }).append(btnEditLib.$element), new OO.ui.FieldLayout(txtPreScript, { label: 'Pre-Process', align: 'top' }).$element, new OO.ui.FieldLayout(txtPostScript, { label: 'Post-Process', align: 'top' }).$element ); addSection('Scripts', $scriptPanel); function updateLibUI() { if (currentLibrary.code) { txtLibStatus.setValue(currentLibrary.name); btnRemoveLib.setDisabled(false); } else { txtLibStatus.setValue('(No library loaded)'); btnRemoveLib.setDisabled(true); } } updateLibUI(); function LibraryEditorDialog(config) { LibraryEditorDialog.super.call(this, config); } OO.inheritClass(LibraryEditorDialog, OO.ui.ProcessDialog); LibraryEditorDialog.static.name = 'libraryEditor'; LibraryEditorDialog.static.title = 'Edit project library'; LibraryEditorDialog.static.actions = [{ action: 'save', label: 'Save', flags: ['primary', 'progressive'] }, { label: 'Cancel', flags: 'safe' } ]; LibraryEditorDialog.prototype.initialize = function() { LibraryEditorDialog.super.prototype.initialize.call(this); this.$element.addClass('wa-lib-dialog'); // Attach our custom CSS override class this.panel = new OO.ui.PanelLayout({ padded: true, expanded: true }); this.$editorWrapper = $('<div>').addClass('wa-lib-editorwrapper'); this.panel.$element.append(this.$editorWrapper); this.$body.append(this.panel.$element); }; LibraryEditorDialog.prototype.getSetupProcess = function(data) { data = data || {}; return LibraryEditorDialog.super.prototype.getSetupProcess.call(this, data) .next(function() { var self = this; self.$editorWrapper.empty(); // Create a textarea for the MediaWiki CM wrapper to properly bind to var $libTextArea = $('<textarea>').appendTo(self.$editorWrapper); var initCode = currentLibrary.code || "// All custom library functions defined here will be passed to the worker.\n// Special functions:\n// function wAwB_Pre(text, vars, shared) { return text; }\n// function wAwB_Post(text, vars, shared) { return text; }\n"; return mw.loader.using(['ext.CodeMirror', 'ext.CodeMirror.modes']).then(function(require) { var CM = require('ext.CodeMirror'); var modes = require('ext.CodeMirror.modes'); self.cmInstance = new CM($libTextArea[0], modes.javascript()); self.cmInstance.initialize(); self.cmInstance.view.dispatch({ changes: { from: 0, insert: initCode } }); // Force CodeMirror to fill the wrapper self.$editorWrapper.find('.cm-editor').css({ height: '100%' }); }).catch(function(err) { console.error("wAwB CM Init Error:", err); }); }, this); }; LibraryEditorDialog.prototype.getActionProcess = function(action) { var dialog = this; if (action === 'save') { return new OO.ui.Process(function() { var newCode = ""; if (dialog.cmInstance) { newCode = dialog.cmInstance.view.state.doc.toString(); } if (newCode.trim() === "") { currentLibrary = { name: null, code: null }; } else { currentLibrary.code = newCode; currentLibrary.name = "custom code"; } updateLibUI(); dialog.close({ action: action }); }); } if (action === 'cancel' || !action) { return new OO.ui.Process(function() { dialog.close({ action: action }); }); } return LibraryEditorDialog.super.prototype.getActionProcess.call(this, action); }; LibraryEditorDialog.prototype.getTeardownProcess = function(data) { return LibraryEditorDialog.super.prototype.getTeardownProcess.call(this, data) .next(function() { if (this.cmInstance) { try { this.cmInstance.view.destroy(); } catch (e) {} this.cmInstance = null; } }, this); }; var windowManager = new OO.ui.WindowManager(); $('body').append(windowManager.$element); var libDialog = new LibraryEditorDialog(); windowManager.addWindows([libDialog]); btnEditLib.on('click', function() { windowManager.openWindow(libDialog); }); var togAdminEnable = new OO.ui.ToggleSwitchWidget({ value: false }); var chkMovRedirect = new OO.ui.CheckboxInputWidget({ selected: false }); var chkMovTalk = new OO.ui.CheckboxInputWidget({ selected: true }); var chkMovSub = new OO.ui.CheckboxInputWidget({ selected: false }); var chkDelTalk = new OO.ui.CheckboxInputWidget({ selected: true }); var dropProtEdit = new OO.ui.DropdownInputWidget({ options: [{ data: '', label: '(No Change)' }, { data: 'all', label: 'All' }, { data: 'autoconfirmed', label: 'Autoconfirmed' }, { data: 'sysop', label: 'Sysop' }] }); var dropProtMove = new OO.ui.DropdownInputWidget({ options: [{ data: '', label: '(No Change)' }, { data: 'all', label: 'All' }, { data: 'autoconfirmed', label: 'Autoconfirmed' }, { data: 'sysop', label: 'Sysop' }] }); var inpProtExpiry = new OO.ui.TextInputWidget({ placeholder: 'infinite / 2 days / 12 hours' }); if (CAN_MOVE || IS_ADMIN) { var $adminPanel = $('<div>').append( $('<div>').css({ 'display': 'flex', 'align-items': 'center', 'justify-content': 'flex-start', 'gap': '10px' }).append($('<span>').text('Enable page actions').css('font-weight', 'bold'), togAdminEnable.$element), $('<hr>') ); if (CAN_MOVE) { $adminPanel.append( $('<strong>').text('Move options:'), new OO.ui.FieldLayout(chkMovRedirect, { label: 'Do not create redirect', align: 'inline' }).$element, new OO.ui.FieldLayout(chkMovTalk, { label: 'Move talk page', align: 'inline' }).$element, new OO.ui.FieldLayout(chkMovSub, { label: 'Move subpages', align: 'inline' }).$element, $('<br>') ); } if (IS_ADMIN) { $adminPanel.append( $('<strong>').text('Delete options:'), new OO.ui.FieldLayout(chkDelTalk, { label: 'Delete talk page', align: 'inline' }).$element, $('<br>'), $('<strong>').text('Protect options:'), new OO.ui.FieldLayout(dropProtEdit, { label: 'Edit level', align: 'top' }).$element, new OO.ui.FieldLayout(dropProtMove, { label: 'Move level', align: 'top' }).$element, new OO.ui.FieldLayout(inpProtExpiry, { label: 'Expiry', align: 'top' }).$element ); } addSection('Page actions', $adminPanel); } var btnPower = new OO.ui.ButtonWidget({ label: 'Start', icon: 'power', flags: ['primary', 'progressive'], title: 'Start editing', accessKey: 'a' }); var btnDiff = new OO.ui.ButtonWidget({ label: 'Diff', icon: 'update', title: 'Show diff', accessKey: 'd' }); var btnSkip = new OO.ui.ButtonWidget({ label: 'Next', icon: 'next', title: 'Skip to next page', accessKey: 'n', disabled: true }); var btnPreview = new OO.ui.ButtonWidget({ label: 'Preview', icon: 'article', title: 'Preview page', accessKey: 'p' }); var btnSave = new OO.ui.ButtonWidget({ label: 'Save', icon: 'upload', flags: 'progressive', title: 'Save edit', accessKey: 's', disabled: true }); var inputSummary = new OO.ui.TextInputWidget({ placeholder: '', value: '', title: 'Enter edit summary', accessKey: 'b' }); var $sumLayout = new OO.ui.FieldLayout(inputSummary, { label: 'Edit summary', align: 'top' }).$element; $sumLayout.css('margin-bottom', '6px'); var listTextarea = new OO.ui.MultilineTextInputWidget({ rows: 15, classes: ['wa-page-list-raw'] }); var btnSort = new OO.ui.ButtonWidget({ icon: 'sortVertical', framed: false }); var btnDedup = new OO.ui.ButtonWidget({ icon: 'funnel', framed: false }); var btnClear = new OO.ui.ButtonWidget({ icon: 'trash', framed: false }); var btnPreParse = new OO.ui.ButtonWidget({ label: 'Pre-parse', title: 'Process list in background', icon: 'robot', framed: false }); var $listCounter = $('<span>').addClass('wa-list-counter').text('0 pages'); var togAutoSave = new OO.ui.ToggleSwitchWidget({ value: false }); var txtAutoDelay = new OO.ui.TextInputWidget({ value: '10' }); var $botRow = $('<div>').addClass('wa-bot-row').hide(); if (PERMS.allowBot) { $botRow.show().append($('<span>').css('font-weight', 'bold').text('Bot mode: '), togAutoSave.$element, $('<span>').text('Delay (s):'), txtAutoDelay.$element.css('max-width', '40px')); togAutoSave.on('change', function(v) { if (v) txtAutoDelay.setValue('10'); }); } var sortAsc = true; var $procHeader = $('<div>').addClass('wa-section-header').attr('id', 'wa-proc-header').css({ 'display': 'flex', 'justify-content': 'space-between', 'align-items': 'center' }); var $procTitle = $('<span>').attr('id', 'wa-proc-title').text('Processing'); var chkMinor = new OO.ui.CheckboxInputWidget({ selected: true, title: 'Minor edit' }); var $minorLayout = new OO.ui.FieldLayout(chkMinor, { label: 'm', align: 'inline', title: 'Minor edit' }); $minorLayout.$element.css({ 'margin-right': '15px', 'font-weight': 'normal' }); $procHeader.append($procTitle, $minorLayout.$element); var $procContent = $('<div>').attr('id', 'wa-proc-content').append( $sumLayout, $botRow, $('<div>').addClass('wa-grid-container').append( $('<div>').addClass('wa-grid-col').append(btnPower.$element), $('<div>').addClass('wa-grid-col').append(btnDiff.$element, btnSkip.$element), $('<div>').addClass('wa-grid-col').append(btnPreview.$element, btnSave.$element) ), $('<div>').addClass('wa-toolbar').append($listCounter, btnSort.$element, btnDedup.$element, btnClear.$element), listTextarea.$element, $('<div>').css({ 'margin-top': '5px' }).append(btnPreParse.$element) ); $content.append($procHeader, $procContent); var configWidgets = [ srcSelect, srcInput, srcInputUser, srcInputStartDate, srcInputEndDate, srcDropProp, chkCatPages, chkCatSub, chkCatFile, chkLinkWiki, chkLinkTrans, chkLinkImg, dropLinkRedir, chkLinkToRedir, btnAdd, redirMode, chkSkipNoChange, radSkipExist, inpSkipContains, togSkipContainsRegex, inpSkipNotContains, togSkipNotContainsRegex, inpSkipCategories, inpSkipNotCategories, dropProtMode, radTargetSet, inpTemplateFilter, btnAddRule, txtPreScript, txtPostScript, chkMovRedirect, chkMovTalk, chkMovSub, chkDelTalk, dropProtEdit, dropProtMove, inpProtExpiry, togWikiTypos, btnLoadLocal, btnClearLocal, btnPreParse ]; // ===================================================================== // 5. FUNCTION DEFINITIONS (Core Logic) // ===================================================================== function checkSummaryWarning() { var val = inputSummary.getValue(); var isBlank = !val || val.trim() === ""; if (isBlank || hasNewSources) inputSummary.$element.addClass('wa-summary-warning'); else inputSummary.$element.removeClass('wa-summary-warning'); } function renderCurrentView() { if (currentViewMode === 'preview') renderPreview(); else renderDiff(); } function toggleConfig(isLocked) { configWidgets.forEach(function(w) { if (w instanceof OO.ui.TextInputWidget || w instanceof OO.ui.MultilineTextInputWidget) { w.setReadOnly(isLocked); w.$element.css('opacity', isLocked ? 0.8 : 1); } else { w.setDisabled(isLocked); } }); $nsSelect.prop('disabled', isLocked); for (var key in protCheckboxes) protCheckboxes[key].setDisabled(isLocked); rulesRegistry.forEach(function(r) { r.find.setReadOnly(isLocked); r.rep.setReadOnly(isLocked); r.regex.setDisabled(isLocked); r.flags.setReadOnly(isLocked); r.enable.setDisabled(isLocked); r.del.setDisabled(isLocked); r.btnFunc.setDisabled(isLocked || !r.regex.getValue()); r.btnUp.setDisabled(isLocked || rulesRegistry.indexOf(r) === 0); r.btnDown.setDisabled(isLocked || rulesRegistry.indexOf(r) === rulesRegistry.length - 1); }); if (CAN_MOVE || IS_ADMIN) togAdminEnable.setDisabled(isLocked); btnLoadLib.setDisabled(isLocked); btnRemoveLib.setDisabled(isLocked || !currentLibrary.code); btnEditLib.setDisabled(isLocked); btnLoadLocal.setDisabled(isLocked); btnClearLocal.setDisabled(isLocked || localTypos.length === 0); } function updateListCount() { var val = listTextarea.getValue(); var count = val.trim() ? val.split('\n').filter(function(l) { var line = l.trim(); return line !== "" && !line.startsWith("####"); }).length : 0; $listCounter.text(count + ' pages'); } listTextarea.on('change', updateListCount); function updateDirtyState() { if (isRunning && currentTitle && Editor.getValue() !== originalWikitext) $editorHeader.addClass('wa-dirty'); else $editorHeader.removeClass('wa-dirty'); } function removeTopLine() { var l = listTextarea.getValue().split('\n'); l.shift(); listTextarea.setValue(l.join('\n')); updateListCount(); } function updateInterfaceMode() { var isAdminMode = togAdminEnable.getValue(); var pageLoaded = !!currentTitle; btnSave.setDisabled(isAdminMode || !pageLoaded || !PERMS.canSave); btnSkip.setDisabled(!pageLoaded); btnPreview.setDisabled(!pageLoaded); btnDiff.setDisabled(isAdminMode || !pageLoaded); Editor.setDisabled(isAdminMode || !pageLoaded); if (CAN_MOVE) { var allowAdmin = isAdminMode && currentPageExists; btnAdminMove.setDisabled(!(allowAdmin && currentVars['$xA'])); if (currentVars['$xA']) btnAdminMove.setTitle('Move page to ' + currentVars['$xA']); else btnAdminMove.setTitle('Move page to $xA (Variable not set)'); } if (IS_ADMIN) { var allowAdmin = isAdminMode && currentPageExists; btnAdminDel.setDisabled(!allowAdmin); btnAdminProt.setDisabled(!allowAdmin); } } function renderDiff() { $visualOut.html('<div style="color:#888; text-align:center;">Generating Diff...</div>'); var currentText = Editor.getValue(); new mw.Api().post({ 'action': 'compare', fromtitle: currentTitle, toslots: 'main', 'totext-main': currentText, slots: 'main', prop: 'diff', formatversion: 2 }).then(function(data) { var diffBody = data.compare && data.compare.bodies && data.compare.bodies.main; if (diffBody) { $visualOut.html('<h4>Diff: ' + currentTitle + '</h4><table class="diff"><colgroup><col class="diff-marker"><col class="diff-content"><col class="diff-marker"><col class="diff-content"></colgroup><tbody>' + diffBody + '</tbody></table>'); processDiffTable(); } else { $visualOut.html('<div style="color:green; text-align:center; padding-top:20px;">No Changes detected</div>'); } }); } function processDiffTable() { var rightLineNum = 0; $visualOut.find('table.diff tr').each(function() { var $tr = $(this); var $linenos = $tr.find('td.diff-lineno'); if ($linenos.length > 0) { var txt = $linenos.last().text(); var m = txt.match(/(\d+)/); if (m) rightLineNum = parseInt(m[1]); return; } if ($tr.find('.diff-addedline').length > 0 || $tr.find('.diff-context').length > 0) { $tr.attr('data-line', rightLineNum); $tr.css('cursor', 'pointer').attr('title', 'Jump to line ' + rightLineNum); rightLineNum++; } }); // Attach a single delegated click listener to the table instead of every row $visualOut.find('table.diff').on('click', 'tr[data-line]', function() { Editor.scrollToLine(parseInt($(this).attr('data-line'))); }); } function renderPreview() { $visualOut.html('<div style="color:#888; text-align:center;">Generating Preview...</div>'); new mw.Api().post({ action: 'parse', title: currentTitle, text: Editor.getValue(), prop: 'text|categorieshtml|modules|jsconfigvars', useskin: mw.config.get('skin'), disablelimitreport: true, pst: true, contentmodel: 'wikitext' }).then(function(data) { if (data.parse && data.parse.text) { var $prev = $('<div>').html(data.parse.text['*']); if (data.parse.categorieshtml) $prev.append(data.parse.categorieshtml['*']); $prev.find('a').attr('target', '_blank'); $visualOut.empty().append($prev); mw.loader.using(data.parse.modules.concat(data.parse.modulestyles, data.parse.modulescripts), function() { mw.hook('wikipage.content').fire($('.wa-visual-output .mw-parser-output')); }); } }).catch(function(err) { $visualOut.html('Error generating preview.'); alert("Preview failed: " + err); }); } async function transformPageText(rawText, title, config) { var filters = config.filters; if (filters) { var check = function(text, rule) { if (!rule || !rule.val) return false; if (rule.regex) { try { return new RegExp(rule.val, 'mu').test(text); } catch (e) { return false; } } return text.indexOf(rule.val) !== -1; }; if (filters.skipContains && filters.skipContains.val && check(rawText, filters.skipContains)) { return { skipped: true, reason: 'Contains: ' + filters.skipContains.val }; } if (filters.skipNotContains && filters.skipNotContains.val && !check(rawText, filters.skipNotContains)) { return { skipped: true, reason: 'Missing: ' + filters.skipNotContains.val }; } } var mode = config.mode; var inputs = []; var compiledSpecies = null; if (config.templateFilter) { var tFilter = config.templateFilter; if (tFilter[0] === "^") tFilter = "^\\{\\{\\s*" + tFilter.slice(1); else tFilter = "\\{\\{\\s*" + tFilter; compiledSpecies = tFilter + "(?=\\s*[|}\\n])"; } var skeleton = PageProtector.protect(rawText, mode, config.excludes, compiledSpecies); if (mode === 'target') inputs = PageProtector.store; else inputs = [skeleton]; var combinedRules = rulesRegistry.filter(r => r.isActive()).map(r => ({ find: r.find.getValue(), replace: r.rep.getValue(), regex: r.regex.getValue(), flags: r.flags.getValue(), enabled: r.isActive(), isFunc: r.isFunc() })); if (togWikiTypos.getValue()) combinedRules = combinedRules.concat(wikiTypos); if (localTypos.length > 0) combinedRules = combinedRules.concat(localTypos); var payload = { texts: inputs, vars: config.vars, preCode: getUserCode(txtPreScript, 'wAwB_Pre'), libraryCode: currentLibrary.code, rules: combinedRules, postCode: getUserCode(txtPostScript, 'wAwB_Post') }; var result = await WorkerEngine.run(payload); if (result.skipped) return { skipped: true, reason: result.reason }; var finalText = ""; if (mode === 'target') { PageProtector.store = result.texts; finalText = PageProtector.restore(skeleton); } else { finalText = PageProtector.restore(result.texts[0]); } return { skipped: false, text: finalText }; } async function processPageContent() { try { setStatus('Processing...', 'working'); var mode = dropProtMode.getValue(); var activeConfig = { mode: mode, excludes: {}, templateFilter: inpTemplateFilter.getValue().trim(), vars: currentVars, filters: { skipContains: { val: inpSkipContains.getValue(), regex: togSkipContainsRegex.getValue() }, skipNotContains: { val: inpSkipNotContains.getValue(), regex: togSkipNotContainsRegex.getValue() } } }; if (mode === 'protect') { for (var k in protCheckboxes) activeConfig.excludes[k] = protCheckboxes[k].isSelected(); } else { var sel = radTargetSet.findSelectedItem(); activeConfig.excludes = sel ? sel.getData() : null; } var res = await transformPageText(originalWikitext, currentTitle, activeConfig); if (res.skipped) { removeTopLine(); loadNextPage(); return; } if (chkSkipNoChange.isSelected() && res.text === originalWikitext) { removeTopLine(); loadNextPage(); return; } setStatus('Ready'); Editor.setValue(res.text); if (CAN_MOVE || IS_ADMIN) updateInterfaceMode(); else { Editor.setDisabled(false); btnSave.setDisabled(!PERMS.canSave); btnSkip.setDisabled(false); btnPreview.setDisabled(false); btnDiff.setDisabled(false); } updateDirtyState(); renderCurrentView(); if (PERMS.allowBot && togAutoSave.getValue()) { var delay = Math.max(0, parseInt(txtAutoDelay.getValue(), 10) || 0) * 1000; setStatus('Auto-save in ' + (delay / 1000) + 's...', 'working'); if (autoSaveTimer) clearTimeout(autoSaveTimer); autoSaveTimer = setTimeout(function() { if (isRunning && PERMS.canSave) { btnSave.emit('click'); } }, delay); } } catch (e) { setStatus('Error', 'error'); alert(e); btnPower.emit('click'); } } async function runPreParseBatch() { // 1. Toggle / Stop Logic if (isRunning) { isRunning = false; setStatus('Stopping...', 'working'); btnPreParse.setLabel('Pre-parse'); return; } // 2. Start & Deduplicate var currentVal = listTextarea.getValue(); var cleanVal = getDeduplicatedList(currentVal).join('\n'); listTextarea.setValue(cleanVal); updateListCount(); isRunning = true; toggleUI(true); // 3. Lock UI toggleUI(true); btnSkip.setDisabled(true); btnDiff.setDisabled(true); btnPreview.setDisabled(true); btnSave.setDisabled(true); Editor.setDisabled(true); btnPreParse.setLabel('Stop pre-parse'); // Inject STOP marker if not present var currentList = listTextarea.getValue().split('\n'); if (!currentList.includes('####STOP')) { currentList.push('####STOP'); listTextarea.setValue(currentList.join('\n')); } // Gather Config var activeConfig = { mode: dropProtMode.getValue(), excludes: {}, templateFilter: inpTemplateFilter.getValue().trim(), vars: {}, filters: { skipContains: { val: inpSkipContains.getValue(), regex: togSkipContainsRegex.getValue() }, skipNotContains: { val: inpSkipNotContains.getValue(), regex: togSkipNotContainsRegex.getValue() } } }; if (activeConfig.mode === 'protect') { for (var k in protCheckboxes) activeConfig.excludes[k] = protCheckboxes[k].isSelected(); } else { var sel = radTargetSet.findSelectedItem(); activeConfig.excludes = sel ? sel.getData() : null; } setStatus('Pre-parsing...', 'working'); while (isRunning) { var lines = listTextarea.getValue().split('\n'); var batchTitles = []; var stopFound = false; for (var i = 0; i < lines.length; i++) { var line = lines[i]; if (line === '####STOP') { stopFound = true; break; } if (line && !line.startsWith('####')) { var parts = line.split('|'); batchTitles.push({ fullLine: line, title: parts[0], vars: parts.slice(1) }); } if (batchTitles.length >= 50) break; } if (batchTitles.length === 0) { if (stopFound) setStatus('Pre-parse complete'); else setStatus('List empty'); break; } $listCounter.text('Fetching ' + batchTitles.length + '...'); var badCats = inpSkipCategories.getValue().split('|').map(s => s.trim()).filter(s => s); var reqCats = inpSkipNotCategories.getValue().split('|').map(s => s.trim()).filter(s => s); var api = new mw.Api(); try { var data = await api.get({ action: 'query', prop: 'revisions' + (badCats.length + reqCats.length > 0 ? '|categories' : ''), titles: batchTitles.map(t => t.title).join('|'), rvprop: 'content', rvslots: 'main', redirects: 1, cllimit: 'max' }); var pageMap = {}; if (data.query && data.query.pages) Object.values(data.query.pages).forEach(p => pageMap[p.title] = p); var redirMap = {}; if (data.query && data.query.redirects) data.query.redirects.forEach(r => redirMap[r.from] = r.to); var keptLines = []; for (var k = 0; k < batchTitles.length; k++) { var item = batchTitles[k]; var lookupTitle = redirMap[item.title] || item.title; var page = pageMap[lookupTitle]; if (!page || page.missing || page.invalid || !page.revisions || !page.revisions[0]) { console.warn("Skipping invalid/missing page:", item.title); continue; } var pageCats = new Set((page.categories || []).map(c => c.title.replace(/^[^:]+:/, '').trim())); if (badCats.some(c => pageCats.has(c))) continue; // Skip if (reqCats.length > 0 && !reqCats.some(c => pageCats.has(c))) continue; // Skip var rawText = page.revisions[0].slots.main['*']; activeConfig.vars = { '$xx': item.title }; item.vars.forEach((v, idx) => activeConfig.vars['$x' + String.fromCharCode(65 + idx)] = v); var res = await transformPageText(rawText, item.title, activeConfig); // UPDATED LOGIC: Respect "Skip if no change" checkbox if (!res.skipped && (!chkSkipNoChange.isSelected() || res.text !== rawText)) { keptLines.push(item.fullLine); } } var freshLines = listTextarea.getValue().split('\n'); var stopIndex = -1; for (var x = 0; x < freshLines.length; x++) { if (freshLines[x] === '####STOP') { stopIndex = x; break; } } if (stopIndex > -1) { var topChunk = freshLines.slice(0, stopIndex); var botChunk = freshLines.slice(stopIndex + 1); var processedSet = new Set(batchTitles.map(t => t.fullLine)); var newTop = topChunk.filter(l => !processedSet.has(l)); var newList = newTop.concat(['####STOP']).concat(botChunk).concat(keptLines); listTextarea.setValue(newList.join('\n')); updateListCount(); } } catch (e) { console.error(e); setStatus('Batch error: ' + e, 'error'); break; } } isRunning = false; toggleUI(false); WorkerEngine.destroy(); btnPreParse.setLabel('Pre-parse'); if (listTextarea.getValue().startsWith('####STOP')) setStatus('Pre-parse done!'); else setStatus('Stopped'); } btnPreParse.on('click', runPreParseBatch); function loadNextPage() { if (!isRunning) return; var allLines = listTextarea.getValue().split('\n'); var listChanged = false; var stopCommand = false; while (allLines.length > 0) { var line = allLines[0]; if (line === '####STOP') { stopCommand = true; break; } if (line.startsWith('####') || line === "") { allLines.shift(); listChanged = true; } else { break; } } if (listChanged) { listTextarea.setValue(allLines.join('\n')); updateListCount(); } if (stopCommand) { btnPower.emit('click'); setStatus("Stopped by ####STOP"); return; } if (allLines.length === 0) { btnPower.emit('click'); setStatus("Done!"); return; } var raw = allLines[0]; var parts = raw.split('|'); currentTitle = parts[0].trim(); baseRevId = 0; originalWikitext = ""; if (!currentTitle) { removeTopLine(); loadNextPage(); return; } currentVars = {}; currentVars['$xx'] = currentTitle; for (var i = 1; i < parts.length; i++) currentVars['$x' + String.fromCharCode(64 + i)] = parts[i]; setStatus('Loading...', 'working'); btnSave.setDisabled(true); btnPreview.setDisabled(true); btnDiff.setDisabled(true); btnSkip.setDisabled(true); Editor.setDisabled(true); $titleLink.attr('href', mw.util.getUrl(currentTitle)).text(currentTitle); $editorHeader.removeClass('wa-dirty'); $visualOut.empty(); Editor.setValue('Loading...'); $infoContainer.empty(); currentPageExists = false; btnWatch.setDisabled(true); if (CAN_MOVE || IS_ADMIN) updateInterfaceMode(); var badCats = inpSkipCategories.getValue().split('|').map(s => s.trim()).filter(s => s); var reqCats = inpSkipNotCategories.getValue().split('|').map(s => s.trim()).filter(s => s); var api = new mw.Api(); var params = { action: 'query', prop: 'revisions|info' + (badCats.length + reqCats.length > 0 ? '|categories' : ''), titles: currentTitle, rvprop: 'content|timestamp|ids', rvslots: 'main', inprop: 'watched', cllimit: 'max' }; var rMode = redirMode.findSelectedItem().getData(); if (rMode === 'follow') params.redirects = 1; return api.get(params).then(async function(data) { var pid = Object.keys(data.query.pages)[0]; var page = data.query.pages[pid]; currentPageExists = !page.missing && !page.invalid; var pageCats = new Set((page.categories || []).map(c => c.title.replace(/^[^:]+:/, '').trim())); if (badCats.some(c => pageCats.has(c))) { setStatus('Skip: cat blacklist'); removeTopLine(); loadNextPage(); return; } if (reqCats.length > 0 && !reqCats.some(c => pageCats.has(c))) { setStatus('Skip: cat whitelist'); removeTopLine(); loadNextPage(); return; } if (rMode === 'follow' && data.query.redirects) { currentTitle = page.title; $titleLink.attr('href', mw.util.getUrl(currentTitle)).text(currentTitle); mw.notify('Redirect followed to: ' + currentTitle); } if (rMode === 'skip' && page.redirect !== undefined) { removeTopLine(); loadNextPage(); return; } var skipMode = radSkipExist.findSelectedItem().getData(); if (pid === "-1") { if (skipMode === 'missing') { removeTopLine(); loadNextPage(); return; } originalWikitext = ""; baseRevId = 0; } else { if (skipMode === 'exists') { removeTopLine(); loadNextPage(); return; } originalWikitext = page.revisions[0].slots.main['*']; baseRevId = page.revisions[0].revid; } if (page.revisions && page.revisions.length > 0) { var rev = page.revisions[0]; var ts = new Date(rev.timestamp).toISOString().replace('T', ' ').substring(0, 16); $infoContainer.empty().append('Last edit: ' + ts + ' | ', $('<a>').attr('href', mw.util.getUrl(currentTitle, { action: 'history' })).attr('target', '_blank').text('history')); } btnWatch.setDisabled(!currentPageExists); if (page.watched !== undefined) btnWatch.setIcon('unStar'); else btnWatch.setIcon('star'); if (CAN_MOVE || IS_ADMIN) { updateInterfaceMode(); if (togAdminEnable.getValue()) { Editor.setValue(originalWikitext); renderCurrentView(); setStatus('Ready (Page actions)'); return; } } processPageContent(); }).catch(function(e) { setStatus('API error', 'error'); alert('Load error: ' + e); btnPower.emit('click'); }); } async function fetchWithContinue(api, params) { var allTitles = new Set(); var continueToken = {}; var safetyLimit = FETCH_SAFETY_LIMIT; var count = 0; isFetching = true; btnAdd.setLabel('Cancel fetch'); $fetchStatus.text('Fetching...').show(); try { while (isFetching && count < safetyLimit) { var merged = Object.assign({}, params, continueToken); var data = await api.get(merged); var batch = []; if (data.watchlistraw) batch = data.watchlistraw; else if (data.query) { if (data.query.pages) batch = Object.values(data.query.pages); else if (data.query.categorymembers) batch = data.query.categorymembers; else if (data.query.backlinks) batch = data.query.backlinks; else if (data.query.embeddedin) batch = data.query.embeddedin; else if (data.query.imageusage) batch = data.query.imageusage; else if (data.query.search) batch = data.query.search; else if (data.query.allpages) batch = data.query.allpages; else if (data.query.usercontribs) batch = data.query.usercontribs; else if (data.query.pageswithprop) batch = data.query.pageswithprop; } if (batch.length > 0) { batch.forEach(item => { if (item.title) allTitles.add(item.title); }); count = allTitles.size; $fetchStatus.text('Fetched ' + count + '...'); } if (data.continue) continueToken = data.continue; else break; } } catch (e) { alert("Fetch interrupted: " + e); } isFetching = false; btnAdd.setLabel('Add to list').setDisabled(false); $fetchStatus.text('Added ' + allTitles.size + ' pages').delay(3000).fadeOut(); if (allTitles.size > 0) { hasNewSources = true; checkSummaryWarning(); } return Array.from(allTitles); } function toggleUI(d) { if (d) { btnPower.setLabel('Stop').setIcon('power').setFlags(['destructive']); } else { btnPower.setLabel('Start').setIcon('power').clearFlags().setFlags(['primary', 'progressive']); if (PERMS.allowBot) togAutoSave.setValue(false); } toggleConfig(d); btnSort.setDisabled(d); btnDedup.setDisabled(d); btnClear.setDisabled(d); btnSaveProj.setDisabled(d); btnLoadProj.setDisabled(d); btnSkip.setDisabled(!d); btnSave.setDisabled(true); listTextarea.setReadOnly(d); if (d) listTextarea.$element.addClass('wa-list-running'); else listTextarea.$element.removeClass('wa-list-running'); } function resetPanels() { Editor.setValue(''); $titleLink.text('Page content').removeAttr('href'); $editorHeader.removeClass('wa-dirty'); setStatus('Ready'); currentTitle = null; $visualOut.html('<div style="color:#aaa; text-align:center; margin-top:50px;">Ready...</div>'); $infoContainer.empty(); btnWatch.setDisabled(true); Editor.setDisabled(true); currentPageExists = false; if (CAN_MOVE || IS_ADMIN) updateInterfaceMode(); toggleUI(false); updateListCount(); if (autoSaveTimer) clearTimeout(autoSaveTimer); } function arrayMove(arr, old_index, new_index) { if (new_index >= arr.length) { var k = new_index - arr.length + 1; while (k--) arr.push(undefined); } arr.splice(new_index, 0, arr.splice(old_index, 1)[0]); } function updateRuleButtons() { rulesRegistry.forEach(function(item, idx) { item.btnUp.setDisabled(idx === 0); item.btnDown.setDisabled(idx === rulesRegistry.length - 1); }); } function addRule() { var row = $('<div>').addClass('wa-rule-row'); var controls = $('<div>').addClass('wa-rule-controls'); var btnUp = new OO.ui.ButtonWidget({ icon: 'collapse', framed: false, title: 'Move up', classes: ['wa-rule-btn'] }); var btnDown = new OO.ui.ButtonWidget({ icon: 'expand', framed: false, title: 'Move down', classes: ['wa-rule-btn'] }); controls.append(btnUp.$element, btnDown.$element); var contentDiv = $('<div>').addClass('wa-rule-content'); var f = new OO.ui.TextInputWidget({ placeholder: 'Find' }); var r = new OO.ui.TextInputWidget({ placeholder: 'Replace' }); var reg = new OO.ui.ToggleSwitchWidget(); var fl = new OO.ui.TextInputWidget({ value: 'gmu', disabled: true }).toggle(false); var btnEnable = new OO.ui.ButtonWidget({ icon: 'power', framed: false, title: 'Toggle rule', flags: ['progressive'] }); var isRuleActive = true; var btnFunc = new OO.ui.ButtonWidget({ icon: 'code', framed: false, title: 'Toggle JS mode', disabled: true }); var isRuleFunc = false; var toggleRule = function(forceVal) { var val = (forceVal !== undefined) ? forceVal : !isRuleActive; isRuleActive = val; row.css('opacity', isRuleActive ? 1 : 0.5); if (isRuleActive) btnEnable.setFlags(['progressive']); else btnEnable.clearFlags(); }; btnEnable.on('click', function() { toggleRule(); }); var toggleFunc = function(forceVal) { var val = (forceVal !== undefined) ? forceVal : !isRuleFunc; isRuleFunc = val; if (isRuleFunc) { btnFunc.setFlags(['progressive']); r.$input.attr('placeholder', 'return match.toUpperCase();'); } else { btnFunc.clearFlags(); r.$input.attr('placeholder', 'Replace'); } }; btnFunc.on('click', function() { toggleFunc(); }); btnFunc.toggle(false); reg.on('change', function(v) { fl.setDisabled(!v); fl.toggle(v); btnFunc.setDisabled(!v); if (!v) { btnFunc.toggle(false); if (isRuleFunc) toggleFunc(false); } else btnFunc.toggle(true); }); var del = new OO.ui.ButtonWidget({ icon: 'trash', flags: 'destructive', framed: false }); del.on('click', function() { row.fadeOut(200, function() { row.remove(); rulesRegistry = rulesRegistry.filter(x => x.row !== row); updateRuleButtons(); }); }); contentDiv.append(f.$element, $('<div>').css('margin-top', '3px').append(r.$element), $('<div>').addClass('wa-rule-opt-row').append($('<div>').css({ 'display': 'flex', 'align-items': 'center' }).append($('<div>').css({ 'display': 'flex', 'align-items': 'center' }).append($('<span>').text('Regex: ').css({ 'font-size': '0.8em', 'margin-right': '4px' }), reg.$element, fl.$element.css({ 'width': '50px', 'margin-left': '5px' })), btnFunc.$element.css('margin-left', '10px')), $('<div>').css('display', 'flex').append(btnEnable.$element, del.$element))); row.append(controls, contentDiv); $rulesList.append(row); var ruleItem = { row: row, find: f, rep: r, regex: reg, flags: fl, btnUp: btnUp, btnDown: btnDown, enable: btnEnable, del: del, btnFunc: btnFunc, isActive: function() { return isRuleActive; }, setActive: toggleRule, isFunc: function() { return isRuleFunc; }, setFunc: toggleFunc }; rulesRegistry.push(ruleItem); btnUp.on('click', function() { var idx = rulesRegistry.indexOf(ruleItem); if (idx > 0) { var prevRow = rulesRegistry[idx - 1].row; row.fadeOut(150, function() { row.insertBefore(prevRow).fadeIn(150).addClass('wa-highlight'); setTimeout(function() { row.removeClass('wa-highlight'); }, 500); }); arrayMove(rulesRegistry, idx, idx - 1); updateRuleButtons(); } }); btnDown.on('click', function() { var idx = rulesRegistry.indexOf(ruleItem); if (idx < rulesRegistry.length - 1) { var nextRow = rulesRegistry[idx + 1].row; row.fadeOut(150, function() { row.insertAfter(nextRow).fadeIn(150).addClass('wa-highlight'); setTimeout(function() { row.removeClass('wa-highlight'); }, 500); }); arrayMove(rulesRegistry, idx, idx + 1); updateRuleButtons(); } }); updateRuleButtons(); } btnAddRule.on('click', addRule); addRule(); togWikiTypos.on('change', function(v) { if (v) { if (wikiTypos.length > 0) lblWikiStatus.text(wikiTypos.length + ' rules loaded (Cached)'); else { lblWikiStatus.text('Fetching...'); togWikiTypos.setDisabled(true); new mw.Api().get({ action: 'query', prop: 'revisions', titles: mw.config.get('wgFormattedNamespaces')[4] + ':AutoWikiBrowser/Typos', rvprop: 'content', rvslots: 'main', formatversion: 2 }).then(function(d) { var page = d.query.pages[0]; if (!page.missing) { wikiTypos = parseTypoContent(page.revisions[0].slots.main.content); lblWikiStatus.text(wikiTypos.length + ' rules loaded'); } else { lblWikiStatus.text('Page not found'); togWikiTypos.setValue(false); } }).catch(function() { lblWikiStatus.text('Error'); togWikiTypos.setValue(false); }).always(function() { togWikiTypos.setDisabled(false); }); } } else lblWikiStatus.text('Rules inactive'); }); btnLoadLocal.on('click', function() { $typoInput.click(); }); $typoInput.on('change', function(e) { var file = e.target.files[0]; if (!file) return; var reader = new FileReader(); reader.onload = function(evt) { localTypos = parseTypoContent(evt.target.result); lblLocalStatus.text(localTypos.length + ' local rules loaded'); btnClearLocal.setDisabled(false); }; reader.readAsText(file); $typoInput.val(''); }); btnClearLocal.on('click', function() { localTypos = []; lblLocalStatus.text('No local rules'); btnClearLocal.setDisabled(true); }); btnLoadLib.on('click', function() { $libInput.click(); }); btnRemoveLib.on('click', function() { currentLibrary = { name: null, code: null }; updateLibUI(); }); $libInput.on('change', function(e) { var file = e.target.files[0]; if (!file) return; var reader = new FileReader(); reader.onload = function(evt) { currentLibrary = { name: file.name, code: evt.target.result }; updateLibUI(); }; reader.readAsText(file); $libInput.val(''); }); btnPower.on('click', function() { hasNewSources = false; checkSummaryWarning(); if (!isRunning) { if (SAVED_SESSION === 0) mw.track('stats.mediawiki_gadget_wAwB_total'); isRunning = true; toggleUI(true); loadNextPage(); } else { if (SAVED_RUN > 0) { mw.track('stats.mediawiki_gadget_wAwB_saved_total', SAVED_RUN, { wiki: WIKI }); SAVED_SESSION += SAVED_RUN; SAVED_RUN = 0; } isRunning = false; toggleUI(false); WorkerEngine.destroy(); resetPanels(); } }); inputSummary.on('change', function() { checkSummaryWarning(); }); btnSkip.on('click', function() { if (Editor.getValue() === 'Loading...') return; removeTopLine(); loadNextPage(); }); btnDiff.on('click', function() { currentViewMode = 'diff'; if (currentTitle) renderDiff(); }); btnPreview.on('click', function() { currentViewMode = 'preview'; if (currentTitle) renderPreview(); }); btnSave.on('click', function() { if (Editor.getValue() === 'Loading...' || !currentTitle) return; if (autoSaveTimer) clearTimeout(autoSaveTimer); btnSave.setDisabled(true); setStatus('Saving...', 'working'); var effectiveDelay = PERMS.saveDelay || 0; if (effectiveDelay > 0) setStatus('Throttling (' + (effectiveDelay / 1000) + 's)...', 'working'); setTimeout(function() { if (effectiveDelay > 0) setStatus('Saving...', 'working'); var summary = inputSummary.getValue() + SUMMARY_SUFFIX; new mw.Api().postWithToken('csrf', { action: 'edit', title: currentTitle, text: Editor.getValue(), summary: summary, minor: chkMinor.isSelected(), baserevid: baseRevId, bot: PERMS.allowBot, tags: DO_TAG ? APP_NAME : undefined }).then(function() { SAVED_RUN += 1; removeTopLine(); loadNextPage(); }).catch(function(c) { btnSave.setDisabled(false); setStatus('Save error', 'error'); alert('Save failed: ' + c); }); }, effectiveDelay); }); btnWatch.on('click', function() { var isWatched = btnWatch.getIcon() === 'unStar'; new mw.Api()[isWatched ? 'unwatch' : 'watch'](currentTitle).then(function() { btnWatch.setIcon(isWatched ? 'star' : 'unStar'); mw.notify(isWatched ? 'Unwatched' : 'Watched'); }); }); btnAdd.on('click', function() { if (isFetching) { isFetching = false; btnAdd.setDisabled(true).setLabel('Cancelling...'); return; } try { var mode = srcSelect.getValue(), q = srcInput.getValue().trim(); if (mode !== 'watchlist' && mode !== 'usercontribs' && mode !== 'pageswithprop' && !q) { alert('Query empty'); return; } var nsIds = ($nsSelect.val() || []).map(v => parseInt(v)); var nsStr = nsIds.join('|'); var api = new mw.Api(), promises = []; if (mode === 'cat') promises.push(fetchWithContinue(api, { action: 'query', list: 'categorymembers', cmtitle: mw.Title.newFromText(q, 14) ? mw.Title.newFromText(q, 14).getPrefixedText() : 'Category:' + q, cmnamespace: nsStr, cmtype: (chkCatPages.isSelected() ? 'page|' : '') + (chkCatSub.isSelected() ? 'subcat|' : '') + (chkCatFile.isSelected() ? 'file' : ''), cmlimit: 'max' })); else if (mode === 'linksto') { if (chkLinkWiki.isSelected()) promises.push(fetchWithContinue(api, { action: 'query', list: 'backlinks', bltitle: q, blnamespace: nsStr, bllimit: 'max', blfilterredir: dropLinkRedir.getValue(), blredirect: chkLinkToRedir.isSelected() })); if (chkLinkTrans.isSelected()) promises.push(fetchWithContinue(api, { action: 'query', list: 'embeddedin', eititle: q, einamespace: nsStr, eilimit: 'max', eifilterredir: dropLinkRedir.getValue() })); if (chkLinkImg.isSelected()) promises.push(fetchWithContinue(api, { action: 'query', list: 'imageusage', iutitle: q, iunamespace: nsStr, iulimit: 'max', iufilterredir: dropLinkRedir.getValue() })); } else if (mode === 'linkson') promises.push(fetchWithContinue(api, { action: 'query', generator: 'links', titles: q, gplnamespace: nsStr, gpllimit: 'max', prop: 'info' })); else if (mode === 'prefix') promises.push(fetchWithContinue(api, { action: 'query', list: 'allpages', apprefix: q, apnamespace: nsIds[0] || 0, aplimit: 'max' })); else if (mode === 'watchlist') promises.push(fetchWithContinue(api, { action: 'query', list: 'watchlistraw', wrnamespace: nsStr, wrlimit: 'max' })); else if (mode === 'search') promises.push(fetchWithContinue(api, { action: 'query', list: 'search', srsearch: q, srnamespace: nsStr, srlimit: 'max' })); else if (mode === 'usercontribs') promises.push(fetchWithContinue(api, { action: 'query', list: 'usercontribs', ucuser: srcInputUser.getValue(), ucstart: srcInputStartDate.getValue(), ucend: srcInputEndDate.getValue(), ucdir: 'newer', uclimit: 'max', ucnamespace: nsStr, ucprop: 'title' })); else if (mode === 'pageswithprop') promises.push(fetchWithContinue(api, { action: 'query', list: 'pageswithprop', pwppropname: srcDropProp.getValue(), pwplimit: 'max' })); Promise.all(promises).then(function(res) { var list = new Set(); res.forEach(titles => titles.forEach(t => list.add(t))); var currentVal = listTextarea.getValue(); var newVal = Array.from(list).join('\n'); listTextarea.setValue(currentVal ? currentVal + '\n' + newVal : newVal); mw.notify('Added ' + list.size + ' pages'); }).catch(e => alert('Error: ' + e)); } catch (e) { alert("Fetch error: " + e); } }); btnSort.on('click', function() { var v = listTextarea.getValue(); if (v) { var lines = getNormalizedList(v); lines.sort((a, b) => sortAsc ? a.localeCompare(b) : b.localeCompare(a)); listTextarea.setValue(lines.join('\n')); sortAsc = !sortAsc; } }); btnDedup.on('click', function() { var v = listTextarea.getValue(); if (v) listTextarea.setValue(getDeduplicatedList(v).join('\n')); }); btnClear.on('click', function() { listTextarea.setValue(''); }); btnSaveProj.on('click', function() { try { var currentMode = srcSelect.getValue(); if (['watchlist', 'usercontribs', 'pageswithprop'].indexOf(currentMode) === -1) queryCache[currentMode] = srcInput.getValue(); var saveExcludes = {}; for (var k in protCheckboxes) saveExcludes[k] = protCheckboxes[k].isSelected(); var data = { version: APP_VERSION, library: currentLibrary, source: { activeMode: currentMode, namespaces: ($nsSelect.val() || []).map(v => parseInt(v)), modes: { cat: { query: queryCache['cat'] || '', options: { pages: chkCatPages.isSelected(), sub: chkCatSub.isSelected(), file: chkCatFile.isSelected() } }, linksto: { query: queryCache['linksto'] || '', options: { wiki: chkLinkWiki.isSelected(), trans: chkLinkTrans.isSelected(), img: chkLinkImg.isSelected(), redir: dropLinkRedir.getValue(), toRedir: chkLinkToRedir.isSelected() } }, linkson: { query: queryCache['linkson'] || '' }, prefix: { query: queryCache['prefix'] || '' }, watchlist: { query: '' }, search: { query: queryCache['search'] || '' }, usercontribs: { options: { user: srcInputUser.getValue(), start: srcInputStartDate.getValue(), end: srcInputEndDate.getValue() } }, pageswithprop: { options: { prop: srcDropProp.getValue() } } } }, settings: { redir: redirMode.findSelectedItem().getData(), skipLogic: radSkipExist.findSelectedItem().getData(), skipNoChange: chkSkipNoChange.isSelected(), minor: chkMinor.isSelected() }, filters: { contains: { val: inpSkipContains.getValue(), regex: togSkipContainsRegex.getValue() }, notContains: { val: inpSkipNotContains.getValue(), regex: togSkipNotContainsRegex.getValue() }, categories: { skip: inpSkipCategories.getValue(), require: inpSkipNotCategories.getValue() } }, rules: rulesRegistry.map(r => ({ find: r.find.getValue(), replace: r.rep.getValue(), regex: r.regex.getValue(), flags: r.flags.getValue(), enabled: r.isActive(), isFunc: r.isFunc() })), scripts: { pre: txtPreScript.getValue(), post: txtPostScript.getValue() }, processing: { summary: inputSummary.getValue(), list: listTextarea.getValue() }, protection: { mode: dropProtMode.getValue(), excludes: saveExcludes, target: (radTargetSet.findSelectedItem() || { getData: () => null }).getData(), templateFilter: inpTemplateFilter.getValue() } }; var a = document.createElement('a'); a.href = URL.createObjectURL(new Blob([JSON.stringify(data, null, 1)], { type: "application/json" })); a.download = "wawb_project.json"; a.click(); } catch (e) { alert("Save error: " + e); } }); btnLoadProj.on('click', function() { $fileInput.click(); }); $fileInput.on('change', function(e) { var file = e.target.files[0]; if (!file) return; var reader = new FileReader(); reader.onload = function(evt) { try { var data = JSON.parse(evt.target.result); isLoadingProject = true; if (data.source) { if (data.source.namespaces) $nsSelect.val(data.source.namespaces.map(String)); if (data.source.modes) { var m = data.source.modes; queryCache = {}; for (var key in m) if (m[key].query !== undefined) queryCache[key] = m[key].query; if (m.cat && m.cat.options) { chkCatPages.setSelected(m.cat.options.pages); chkCatSub.setSelected(m.cat.options.sub); chkCatFile.setSelected(m.cat.options.file); } if (m.linksto && m.linksto.options) { chkLinkWiki.setSelected(m.linksto.options.wiki); chkLinkTrans.setSelected(m.linksto.options.trans); chkLinkImg.setSelected(m.linksto.options.img); dropLinkRedir.setValue(m.linksto.options.redir); chkLinkToRedir.setSelected(m.linksto.options.toRedir); } if (m.usercontribs && m.usercontribs.options) { srcInputUser.setValue(m.usercontribs.options.user); srcInputStartDate.setValue(m.usercontribs.options.start); srcInputEndDate.setValue(m.usercontribs.options.end); } if (m.pageswithprop && m.pageswithprop.options) srcDropProp.setValue(m.pageswithprop.options.prop); } if (data.source.activeMode) { srcSelect.setValue(data.source.activeMode); isLoadingProject = false; srcSelect.emit('change', data.source.activeMode); isLoadingProject = true; } } if (data.settings) { redirMode.selectItemByData(data.settings.redir); chkSkipNoChange.setSelected(data.settings.skipNoChange); radSkipExist.selectItemByData(data.settings.skipLogic); if (data.settings.minor !== undefined) chkMinor.setSelected(data.settings.minor); } if (data.protection) { dropProtMode.setValue(data.protection.mode); for (var k in data.protection.excludes) if (protCheckboxes[k]) protCheckboxes[k].setSelected(data.protection.excludes[k]); if (data.protection.target) radTargetSet.selectItemByData(data.protection.target); if (data.protection.templateFilter) inpTemplateFilter.setValue(data.protection.templateFilter); } if (data.library) { currentLibrary = data.library; updateLibUI(); } if (data.filters) { inpSkipContains.setValue(data.filters.contains.val); togSkipContainsRegex.setValue(data.filters.contains.regex); inpSkipNotContains.setValue(data.filters.notContains.val); togSkipNotContainsRegex.setValue(data.filters.notContains.regex); } if (data.filters.categories) { inpSkipCategories.setValue(data.filters.categories.skip); inpSkipNotCategories.setValue(data.filters.categories.require); } rulesRegistry.forEach(r => r.row.remove()); rulesRegistry = []; $rulesList.empty(); if (data.rules) data.rules.forEach(r => { addRule(); var last = rulesRegistry[rulesRegistry.length - 1]; last.find.setValue(r.find); last.rep.setValue(r.replace); last.regex.setValue(r.regex); last.flags.setValue(r.flags); last.flags.setDisabled(!r.regex); last.setActive(r.enabled); if (r.isFunc) last.setFunc(true); }); if (rulesRegistry.length === 0) addRule(); if (data.scripts) { txtPreScript.setValue(data.scripts.pre); txtPostScript.setValue(data.scripts.post); } if (data.processing) { inputSummary.setValue(data.processing.summary); listTextarea.setValue(data.processing.list); } isLoadingProject = false; setStatus('Project loaded'); } catch (err) { alert("Error: " + err); } $fileInput.val(''); }; reader.readAsText(file); }); if (CAN_MOVE || IS_ADMIN) { togAdminEnable.on('change', function(val) { if (!currentTitle) { updateInterfaceMode(); return; } if (val) { Editor.setValue(originalWikitext); updateInterfaceMode(); renderDiff(); setStatus('Ready (Page actions)'); } else processPageContent(); }); } if (CAN_MOVE) { btnAdminMove.on('click', function() { if (!currentVars['$xA']) { mw.notify('Variable $xA not set', { type: 'error' }); return; } new mw.Api().postWithToken('csrf', { action: 'move', from: currentTitle, to: currentVars['$xA'], reason: inputSummary.getValue() + SUMMARY_SUFFIX, movetalk: chkMovTalk.isSelected(), movesubpages: chkMovSub.isSelected(), noredirect: chkMovRedirect.isSelected() }).then(function() { removeTopLine(); loadNextPage(); }).catch(e => alert('Move failed: ' + e)); }); } if (IS_ADMIN) { btnAdminDel.on('click', function() { new mw.Api().postWithToken('csrf', { action: 'delete', title: currentTitle, reason: inputSummary.getValue() + SUMMARY_SUFFIX }).then(function() { if (chkDelTalk.isSelected()) new mw.Api().postWithToken('csrf', { action: 'delete', title: mw.Title.newFromText(currentTitle).getTalkPage().getPrefixedText(), reason: 'Talk page of deleted page' }); removeTopLine(); loadNextPage(); }).catch(e => alert('Delete failed: ' + e)); }); btnAdminProt.on('click', function() { var protections = []; if (dropProtEdit.getValue()) protections.push('edit=' + dropProtEdit.getValue()); if (dropProtMove.getValue()) protections.push('move=' + dropProtMove.getValue()); new mw.Api().postWithToken('csrf', { action: 'protect', title: currentTitle, protections: protections.join('|'), expiry: inpProtExpiry.getValue() || 'infinite', reason: inputSummary.getValue() + SUMMARY_SUFFIX }).then(function() { removeTopLine(); loadNextPage(); }).catch(e => alert('Protect failed: ' + e)); }); } Editor.init(); resetPanels(); }); $(window).on('beforeunload', function() { return "You have unsaved work."; }); }).catch(e => console.error("wAwB Loader Error:", e)); //</nowiki> i16q8vtkk7a3dly5y4hjetvm1w32wjq Vikipediya:Addəyişmə müraciətləri 0 174535 739018 735469 2026-04-21T13:50:43Z ~2026-23062-17 73557 showcaptcha 739018 wikitext text/x-wiki {{subst:yeni addəyişmə müraciəti|1=Azala|2=asdfjasdjfjasdjfdsaj|3=mirta [[User:Əkrəm|<span style="padding: 4px 6px; background-color: black; color: white; font-weight: bold">əkrəm<span style="color: #ABABAB">.</span></span>]] 23:31, 27 March 2026 (UTC)}} {{subst:Vikipediya:Addəyişmə müraciətləri/Yeni müraciət|1=Avoidant personality disorder|2=mdasfmdsmfasmd|3=mırta [[User:Əkrəm|<span style="padding: 4px 6px; background-color: black; color: white; font-weight: bold">əkrəm<span style="color: #ABABAB">.</span></span>]] 00:54, 28 March 2026 (UTC)}} {{subst:Vikipediya:Addəyişmə müraciətləri/Yeni müraciət |1= Azala |2= asdfasdfdasfas|3= nəbilime [[User:Əkrəm|<span style="padding: 4px 6px; background-color: black; color: white; font-weight: bold">əkrəm<span style="color: #ABABAB">.</span></span>]] 03:38, 28 March 2026 (UTC) }} this is an edit ardaz7b9pkuipogmp1e5fe2hgrmm9se User:Axwvwxz/Pywikibot Test 2 174956 739021 2026-04-21T15:06:14Z Axwvwxz 73360 Creating a test subpage 739021 wikitext text/x-wiki This is a brand new page created via Termux and Pywikibot! f7n43cava8pp6k8gmu08j8n74aa0lrn 739025 739021 2026-04-21T15:19:34Z Axwvwxz 73360 Batch update using PageGenerator 739025 wikitext text/x-wiki This is a brand new page created via Termux and Pywikibot! Updated by Auto-Pilot Mode 🚀 gswueu167r2u6ohdb1gch6iqoj2gsnh User:Axwvwxz/Test Page 1 2 174957 739022 2026-04-21T15:15:00Z Axwvwxz 73360 Testing mass edit on 3 pages 739022 wikitext text/x-wiki This is an automated message on User:Axwvwxz/Test_Page_1. Status: Level 2 Automation Successful! j63bvs0hphrdj10xdo6p9yv0not9bvz 739026 739022 2026-04-21T15:19:44Z Axwvwxz 73360 Batch update using PageGenerator 739026 wikitext text/x-wiki This is an automated message on User:Axwvwxz/Test_Page_1. Status: Level 2 Automation Successful! Updated by Auto-Pilot Mode 🚀 on834jeuyt5carbxf3atoz7xuog3128 User:Axwvwxz/Test Page 2 2 174958 739023 2026-04-21T15:15:10Z Axwvwxz 73360 Testing mass edit on 3 pages 739023 wikitext text/x-wiki This is an automated message on User:Axwvwxz/Test_Page_2. Status: Level 2 Automation Successful! dfxhakdflrgklwc0kdcee6ui8z7m207 739027 739023 2026-04-21T15:19:54Z Axwvwxz 73360 Batch update using PageGenerator 739027 wikitext text/x-wiki This is an automated message on User:Axwvwxz/Test_Page_2. Status: Level 2 Automation Successful! Updated by Auto-Pilot Mode 🚀 f0e3kcrjqvuj2bryh2ns5pfpp27duwr User:Axwvwxz/Test Page 3 2 174959 739024 2026-04-21T15:15:20Z Axwvwxz 73360 Testing mass edit on 3 pages 739024 wikitext text/x-wiki This is an automated message on User:Axwvwxz/Test_Page_3. Status: Level 2 Automation Successful! 8e4ho54soybzi9dkvqrefa8h3asrdbj 739028 739024 2026-04-21T15:20:04Z Axwvwxz 73360 Batch update using PageGenerator 739028 wikitext text/x-wiki This is an automated message on User:Axwvwxz/Test_Page_3. Status: Level 2 Automation Successful! Updated by Auto-Pilot Mode 🚀 eokdunsybmh058ew23ic41bn9wrd01n .gb 0 174960 739036 2026-04-21T15:58:06Z MPostoronca-WMF 72719 test 739036 wikitext text/x-wiki testing source editor on mobile ek8idou1kcb26jn0ep22xtqtl0l42ne Template:Autoarchive 10 174963 739050 2026-04-21T23:29:03Z AsteraBot 69554 Let's hope this works 739050 wikitext text/x-wiki <includeonly> {{{archive|}}}{{{ago|}}} </includeonly> d342moc1wia7la600qvkpwhetf37ukt 739051 739050 2026-04-21T23:46:39Z AsteraBot 69554 fix 739051 wikitext text/x-wiki {{{archive|}}}{{{ago|}}} 1tipnph5730ibnjsg1qbo0bphptel02 739053 739051 2026-04-22T00:12:57Z AsteraBot 69554 Fix?? 739053 wikitext text/x-wiki <includeonly><!-- AUTOARCHIVE CONFIG --> {{{archive|}}}||{{{ago|}}} </includeonly> 6wz0uywc28vsqmydzuvxwtdxmfbeh77 739055 739053 2026-04-22T00:19:06Z AsteraBot 69554 There's only one way left 739055 wikitext text/x-wiki <includeonly> <!-- Autoarchive config: intentionally empty --> </includeonly> e2rv7bpvr5g5rv0zhqxrrzm0h2ahfaj User talk:AsteraBot 3 174964 739058 2026-04-22T00:27:03Z AsteraBot 69554 Lazy copy-paste testing 739058 wikitext text/x-wiki {{Autoarchive |archive=%(fullpage)/Archives/%(year) |ago=2m }} == Justarandomamerican (Steward)== <div class="boilerplate metadata discussion-archived" style="background-color: #F2F4FC; margin: 2em 0 0 0; padding: 0 10px 0 10px; border: 1px solid #aaa"> :''The following discussion is closed. <b style="color:red">Please do not modify it</b>. Subsequent comments should be made in a new section.'' ::With the unanimous support of 9 community members, this request is '''successful'''. Congratulations on being the first officially elected steward and welcome (back?) to the team! :) [[User:Globe|Globe]] ([[User talk:Globe|talk]]) 21:10, 21 April 2026 (UTC) ---- Hello! I'm Justarandomamerican, and I am filing a request for stewardship, because the board has abolished the staff role, and for staff members to keep their permissions, they must stand for election. I've been here since 2024, when the farm was founded. I hope the community trusts me. Thank you for your time! [[User:Justarandomamerican|Justarandomamerican]] ([[User talk:Justarandomamerican|talk]]) 21:10, 16 April 2026 (UTC) :<small> This candidate has signed an NDA with the WikiOasis Foundation, as is required for stewardship. [[User:Justarandomamerican|Justarandomamerican]] ([[User talk:Justarandomamerican|talk]]) 01:23, 17 April 2026 (UTC)</small> === Questions === In the interests of making this more of an interesting process than a formality, I have a few questions which more or less mirror to all candidates. Some I admit are bundled questions, feel free to answer to the extent applicable. # Based on your request, what do you currently do that requires Steward capabilities? # Do you believe you have made mistakes in your official capacity on this platform so far? If so, what did you do to improve from those mistakes? You could elaborate on just one if you like, or a couple. # What is your vision of what a steward is, and what they do for the community? # Two users appear in the CheckUser interface who both appear to be using Tor who are regular editors on a large wiki, which is also being attacked seemingly out of nowhere by an assailant who is using Tor and free VPNs. Is this a slam dunk connection, if your review of edits suggest their editing styles are similar (but no major stylistic tells)? Why/why not, and if not, what's the next step to find out? # How would you close a vote proposing a change in which seven people essentially say support and maybe a few words, nothing really in depth, and three people have articulated major concerns with the proposal at the level of detail of these questions? Would that process change if it was only one oppose like this to seven support, and if that oppose appeared just before you were going to close the RfC? Thank you, --'''[[User:Raidarr|raidarr]]''' '''('''[[User_talk:Raidarr|📡]]''')''' 22:45, 17 April 2026 (UTC) :Hello! Sorry I was unable to respond; I have other things going on. :# CheckUser and Oversight, definitely; I need those to help with abuse and help our wikis out. :# Oh yes, definitely. I have made mistakes, including unauthorized usage of Foundation funds. I have been working on impulse control, and will be in therapy for the foreseeable future. Thank you for asking. :# A steward is, fundamentally, a community representative. I represent the community, even though I might have some control over it, I shouldn't use it in an authoritarian manner. :# This does not seem to be a slam dunk connection. I would keep watching their contribs to find out. :# First one, would close as unsuccessful, it is not a consensus to have several support votes with no words, and a few major concerns articulated in detail. Second one, would relist. All opinions should have a chance to be considered, no matter how late they appeared. :[[User:Justarandomamerican|Justarandomamerican]] ([[User talk:Justarandomamerican|talk]]) 15:27, 20 April 2026 (UTC) A few questions targeted towards individual candidates across the process: # How do you see your history as president of the WikiOasis Foundation fits into this role, and the trust that the community will be placing in you that may not yet have been rebuilt? # What do you think that you would bring to the steward team that other candidates may not? # Can you discuss what your reasoning behind [https://italianbrainrot.wikioasis.org/wiki/Special:Log?logid=23008 this] was, as there were local administrators at the time who could've handled this apparent one off incident? # How do you feel that team discussion fits into the handling of appeals by banned and locked users, do you think that an appeal should be solely handled by one person without discussion? Best, --'''[[User:Zippy|zippy]]'''[[User talk:Zippy|bonzo]]''' ([[Special:Contributions/Zippy|c]] • [[Special:CentralAuth/Zippy|ca]]) 00:14, 18 April 2026 (UTC) :# Honestly, I see it fitting into this role somewhat. It was a major breach of trust, and I have worked on myself since then. I just hope it never happens again, with anybody. :# There are numerous experienced candidates, so nothing new there. I might just bring my track record of good behavior since the Foundation incident. :# That was clear and obvious vandalism, which can be handled by anyone with rights to delete, including GPs and GAs. :# I think there should be team discussion around appeals. One person handling it doesn't seem good, as they may be biased. :[[User:Justarandomamerican|Justarandomamerican]] ([[User talk:Justarandomamerican|talk]]) 15:32, 20 April 2026 (UTC) === Discussion === # {{support}}, has a clue, not a jerk --'''[[User:Zippy|zippy]]'''[[User talk:Zippy|bonzo]]''' ([[Special:Contributions/Zippy|c]] • [[Special:CentralAuth/Zippy|ca]]) 01:14, 17 April 2026 (UTC) #{{Support}} [[User:SleepingElephant2145|SleepingElephant2145]] ([[User talk:SleepingElephant2145|talk]]) 01:20, 17 April 2026 (UTC) # I have noticed Justarandomamerican around testwiki.wiki (where they serve as system admin/steward) and can {{support}} this request. <span style="font-family:Courier New;font-weight:bold;text-shadow:1px 1px 1px cyan">[[User:Tester|Tester]]</span> ([[User_talk:Tester|ᴛ]]•[[Special:Contributions/Tester|ᴄ]]) 01:40, 17 April 2026 (UTC) # {{Support|strongest}} <span style="background:#EFD8FD;color:Indigo;font-family:serif">~&nbsp;'''''[[User:Dream Indigo|<span style="color:Indigo">Dream Indigo</span>]]'''''&nbsp;[[User talk:Dream Indigo|<span style="color:Indigo">✩</span>]]</span> 01:49, 17 April 2026 (UTC) # No brainer {{support}}. [[User:Globe|Globe]] ([[User talk:Globe|talk]]) 01:53, 17 April 2026 (UTC) # Ex-Board Member and is trusted within the WikiOasis Volunteers. No brainer {{support}}. [[User:Fearless|Fearless]] ([[User talk:Fearless|talk]]) 10:22, 17 April 2026 (UTC) # {{Support}} --[[User:PinkPugPrincess|PinkPugPrincess]] ([[User talk:PinkPugPrincess|talk]]) 13:36, 17 April 2026 (UTC) # {{Support|Strongest}} [[User:AlPaD|AlPaD]] ([[User talk:AlPaD|talk]]) 14:52, 17 April 2026 (UTC) # {{Support}} No Concerns --[[User:Cocopuff2018|Cocopuff2018]] ([[User talk:Cocopuff2018|talk]]) 16:36, 17 April 2026 (UTC) ---- :''The above discussion is preserved as an archive. <b style="color:red">Please do not modify it</b>. Subsequent comments should be made in a new section.'' </div> qogasqzfdelv0ysbj7ir85jjiq1gr0x 739060 739058 2026-04-22T00:36:03Z AsteraBot 69554 Bot: removing archived sections 739060 wikitext text/x-wiki {{Autoarchive |archive=%(fullpage)/Archives/%(year) |ago=2m }} === Questions === In the interests of making this more of an interesting process than a formality, I have a few questions which more or less mirror to all candidates. Some I admit are bundled questions, feel free to answer to the extent applicable. # Based on your request, what do you currently do that requires Steward capabilities? # Do you believe you have made mistakes in your official capacity on this platform so far? If so, what did you do to improve from those mistakes? You could elaborate on just one if you like, or a couple. # What is your vision of what a steward is, and what they do for the community? # Two users appear in the CheckUser interface who both appear to be using Tor who are regular editors on a large wiki, which is also being attacked seemingly out of nowhere by an assailant who is using Tor and free VPNs. Is this a slam dunk connection, if your review of edits suggest their editing styles are similar (but no major stylistic tells)? Why/why not, and if not, what's the next step to find out? # How would you close a vote proposing a change in which seven people essentially say support and maybe a few words, nothing really in depth, and three people have articulated major concerns with the proposal at the level of detail of these questions? Would that process change if it was only one oppose like this to seven support, and if that oppose appeared just before you were going to close the RfC? Thank you, --'''[[User:Raidarr|raidarr]]''' '''('''[[User_talk:Raidarr|📡]]''')''' 22:45, 17 April 2026 (UTC) :Hello! Sorry I was unable to respond; I have other things going on. :# CheckUser and Oversight, definitely; I need those to help with abuse and help our wikis out. :# Oh yes, definitely. I have made mistakes, including unauthorized usage of Foundation funds. I have been working on impulse control, and will be in therapy for the foreseeable future. Thank you for asking. :# A steward is, fundamentally, a community representative. I represent the community, even though I might have some control over it, I shouldn't use it in an authoritarian manner. :# This does not seem to be a slam dunk connection. I would keep watching their contribs to find out. :# First one, would close as unsuccessful, it is not a consensus to have several support votes with no words, and a few major concerns articulated in detail. Second one, would relist. All opinions should have a chance to be considered, no matter how late they appeared. :[[User:Justarandomamerican|Justarandomamerican]] ([[User talk:Justarandomamerican|talk]]) 15:27, 20 April 2026 (UTC) A few questions targeted towards individual candidates across the process: # How do you see your history as president of the WikiOasis Foundation fits into this role, and the trust that the community will be placing in you that may not yet have been rebuilt? # What do you think that you would bring to the steward team that other candidates may not? # Can you discuss what your reasoning behind [https://italianbrainrot.wikioasis.org/wiki/Special:Log?logid=23008 this] was, as there were local administrators at the time who could've handled this apparent one off incident? # How do you feel that team discussion fits into the handling of appeals by banned and locked users, do you think that an appeal should be solely handled by one person without discussion? Best, --'''[[User:Zippy|zippy]]'''[[User talk:Zippy|bonzo]]''' ([[Special:Contributions/Zippy|c]] • [[Special:CentralAuth/Zippy|ca]]) 00:14, 18 April 2026 (UTC) :# Honestly, I see it fitting into this role somewhat. It was a major breach of trust, and I have worked on myself since then. I just hope it never happens again, with anybody. :# There are numerous experienced candidates, so nothing new there. I might just bring my track record of good behavior since the Foundation incident. :# That was clear and obvious vandalism, which can be handled by anyone with rights to delete, including GPs and GAs. :# I think there should be team discussion around appeals. One person handling it doesn't seem good, as they may be biased. :[[User:Justarandomamerican|Justarandomamerican]] ([[User talk:Justarandomamerican|talk]]) 15:32, 20 April 2026 (UTC) === Discussion === # {{support}}, has a clue, not a jerk --'''[[User:Zippy|zippy]]'''[[User talk:Zippy|bonzo]]''' ([[Special:Contributions/Zippy|c]] • [[Special:CentralAuth/Zippy|ca]]) 01:14, 17 April 2026 (UTC) #{{Support}} [[User:SleepingElephant2145|SleepingElephant2145]] ([[User talk:SleepingElephant2145|talk]]) 01:20, 17 April 2026 (UTC) # I have noticed Justarandomamerican around testwiki.wiki (where they serve as system admin/steward) and can {{support}} this request. <span style="font-family:Courier New;font-weight:bold;text-shadow:1px 1px 1px cyan">[[User:Tester|Tester]]</span> ([[User_talk:Tester|ᴛ]]•[[Special:Contributions/Tester|ᴄ]]) 01:40, 17 April 2026 (UTC) # {{Support|strongest}} <span style="background:#EFD8FD;color:Indigo;font-family:serif">~&nbsp;'''''[[User:Dream Indigo|<span style="color:Indigo">Dream Indigo</span>]]'''''&nbsp;[[User talk:Dream Indigo|<span style="color:Indigo">✩</span>]]</span> 01:49, 17 April 2026 (UTC) # No brainer {{support}}. [[User:Globe|Globe]] ([[User talk:Globe|talk]]) 01:53, 17 April 2026 (UTC) # Ex-Board Member and is trusted within the WikiOasis Volunteers. No brainer {{support}}. [[User:Fearless|Fearless]] ([[User talk:Fearless|talk]]) 10:22, 17 April 2026 (UTC) # {{Support}} --[[User:PinkPugPrincess|PinkPugPrincess]] ([[User talk:PinkPugPrincess|talk]]) 13:36, 17 April 2026 (UTC) # {{Support|Strongest}} [[User:AlPaD|AlPaD]] ([[User talk:AlPaD|talk]]) 14:52, 17 April 2026 (UTC) # {{Support}} No Concerns --[[User:Cocopuff2018|Cocopuff2018]] ([[User talk:Cocopuff2018|talk]]) 16:36, 17 April 2026 (UTC) ---- :''The above discussion is preserved as an archive. <b style="color:red">Please do not modify it</b>. Subsequent comments should be made in a new section.'' </div> kvmaed6ahkvknqgxhv92vzcwe5rtoil 739061 739060 2026-04-22T00:48:53Z AsteraBot 69554 Retrying 739061 wikitext text/x-wiki {{Autoarchive |archive=%(fullpage)/Archives/%(year) |ago=2m }} == Justarandomamerican (Steward)== <div class="boilerplate metadata discussion-archived" style="background-color: #F2F4FC; margin: 2em 0 0 0; padding: 0 10px 0 10px; border: 1px solid #aaa"> :''The following discussion is closed. <b style="color:red">Please do not modify it</b>. Subsequent comments should be made in a new section.'' ::With the unanimous support of 9 community members, this request is '''successful'''. Congratulations on being the first officially elected steward and welcome (back?) to the team! :) [[User:Globe|Globe]] ([[User talk:Globe|talk]]) 21:10, 21 April 2026 (UTC) ---- Hello! I'm Justarandomamerican, and I am filing a request for stewardship, because the board has abolished the staff role, and for staff members to keep their permissions, they must stand for election. I've been here since 2024, when the farm was founded. I hope the community trusts me. Thank you for your time! [[User:Justarandomamerican|Justarandomamerican]] ([[User talk:Justarandomamerican|talk]]) 21:10, 16 April 2026 (UTC) :<small> This candidate has signed an NDA with the WikiOasis Foundation, as is required for stewardship. [[User:Justarandomamerican|Justarandomamerican]] ([[User talk:Justarandomamerican|talk]]) 01:23, 17 April 2026 (UTC)</small> === Questions === In the interests of making this more of an interesting process than a formality, I have a few questions which more or less mirror to all candidates. Some I admit are bundled questions, feel free to answer to the extent applicable. # Based on your request, what do you currently do that requires Steward capabilities? # Do you believe you have made mistakes in your official capacity on this platform so far? If so, what did you do to improve from those mistakes? You could elaborate on just one if you like, or a couple. # What is your vision of what a steward is, and what they do for the community? # Two users appear in the CheckUser interface who both appear to be using Tor who are regular editors on a large wiki, which is also being attacked seemingly out of nowhere by an assailant who is using Tor and free VPNs. Is this a slam dunk connection, if your review of edits suggest their editing styles are similar (but no major stylistic tells)? Why/why not, and if not, what's the next step to find out? # How would you close a vote proposing a change in which seven people essentially say support and maybe a few words, nothing really in depth, and three people have articulated major concerns with the proposal at the level of detail of these questions? Would that process change if it was only one oppose like this to seven support, and if that oppose appeared just before you were going to close the RfC? Thank you, --'''[[User:Raidarr|raidarr]]''' '''('''[[User_talk:Raidarr|📡]]''')''' 22:45, 17 April 2026 (UTC) :Hello! Sorry I was unable to respond; I have other things going on. :# CheckUser and Oversight, definitely; I need those to help with abuse and help our wikis out. :# Oh yes, definitely. I have made mistakes, including unauthorized usage of Foundation funds. I have been working on impulse control, and will be in therapy for the foreseeable future. Thank you for asking. :# A steward is, fundamentally, a community representative. I represent the community, even though I might have some control over it, I shouldn't use it in an authoritarian manner. :# This does not seem to be a slam dunk connection. I would keep watching their contribs to find out. :# First one, would close as unsuccessful, it is not a consensus to have several support votes with no words, and a few major concerns articulated in detail. Second one, would relist. All opinions should have a chance to be considered, no matter how late they appeared. :[[User:Justarandomamerican|Justarandomamerican]] ([[User talk:Justarandomamerican|talk]]) 15:27, 20 April 2026 (UTC) A few questions targeted towards individual candidates across the process: # How do you see your history as president of the WikiOasis Foundation fits into this role, and the trust that the community will be placing in you that may not yet have been rebuilt? # What do you think that you would bring to the steward team that other candidates may not? # Can you discuss what your reasoning behind [https://italianbrainrot.wikioasis.org/wiki/Special:Log?logid=23008 this] was, as there were local administrators at the time who could've handled this apparent one off incident? # How do you feel that team discussion fits into the handling of appeals by banned and locked users, do you think that an appeal should be solely handled by one person without discussion? Best, --'''[[User:Zippy|zippy]]'''[[User talk:Zippy|bonzo]]''' ([[Special:Contributions/Zippy|c]] • [[Special:CentralAuth/Zippy|ca]]) 00:14, 18 April 2026 (UTC) :# Honestly, I see it fitting into this role somewhat. It was a major breach of trust, and I have worked on myself since then. I just hope it never happens again, with anybody. :# There are numerous experienced candidates, so nothing new there. I might just bring my track record of good behavior since the Foundation incident. :# That was clear and obvious vandalism, which can be handled by anyone with rights to delete, including GPs and GAs. :# I think there should be team discussion around appeals. One person handling it doesn't seem good, as they may be biased. :[[User:Justarandomamerican|Justarandomamerican]] ([[User talk:Justarandomamerican|talk]]) 15:32, 20 April 2026 (UTC) === Discussion === # {{support}}, has a clue, not a jerk --'''[[User:Zippy|zippy]]'''[[User talk:Zippy|bonzo]]''' ([[Special:Contributions/Zippy|c]] • [[Special:CentralAuth/Zippy|ca]]) 01:14, 17 April 2026 (UTC) #{{Support}} [[User:SleepingElephant2145|SleepingElephant2145]] ([[User talk:SleepingElephant2145|talk]]) 01:20, 17 April 2026 (UTC) # I have noticed Justarandomamerican around testwiki.wiki (where they serve as system admin/steward) and can {{support}} this request. <span style="font-family:Courier New;font-weight:bold;text-shadow:1px 1px 1px cyan">[[User:Tester|Tester]]</span> ([[User_talk:Tester|ᴛ]]•[[Special:Contributions/Tester|ᴄ]]) 01:40, 17 April 2026 (UTC) # {{Support|strongest}} <span style="background:#EFD8FD;color:Indigo;font-family:serif">~&nbsp;'''''[[User:Dream Indigo|<span style="color:Indigo">Dream Indigo</span>]]'''''&nbsp;[[User talk:Dream Indigo|<span style="color:Indigo">✩</span>]]</span> 01:49, 17 April 2026 (UTC) # No brainer {{support}}. [[User:Globe|Globe]] ([[User talk:Globe|talk]]) 01:53, 17 April 2026 (UTC) # Ex-Board Member and is trusted within the WikiOasis Volunteers. No brainer {{support}}. [[User:Fearless|Fearless]] ([[User talk:Fearless|talk]]) 10:22, 17 April 2026 (UTC) # {{Support}} --[[User:PinkPugPrincess|PinkPugPrincess]] ([[User talk:PinkPugPrincess|talk]]) 13:36, 17 April 2026 (UTC) # {{Support|Strongest}} [[User:AlPaD|AlPaD]] ([[User talk:AlPaD|talk]]) 14:52, 17 April 2026 (UTC) # {{Support}} No Concerns --[[User:Cocopuff2018|Cocopuff2018]] ([[User talk:Cocopuff2018|talk]]) 16:36, 17 April 2026 (UTC) ---- :''The above discussion is preserved as an archive. <b style="color:red">Please do not modify it</b>. Subsequent comments should be made in a new section.'' </div> qogasqzfdelv0ysbj7ir85jjiq1gr0x 739064 739061 2026-04-22T00:54:01Z AsteraBot 69554 Bot: removing archived sections 739064 wikitext text/x-wiki {{Autoarchive |archive=%(fullpage)/Archives/%(year) |ago=2m }} == Justarandomamerican (Steward)== g1pgicnojfch2hncaptm04sm3cg8sjx 739065 739064 2026-04-22T00:56:15Z AsteraBot 69554 Trying again 739065 wikitext text/x-wiki {{Autoarchive |archive=%(fullpage)/Archives/%(year) |ago=2m }} == Justarandomamerican (Steward)== <div class="boilerplate metadata discussion-archived" style="background-color: #F2F4FC; margin: 2em 0 0 0; padding: 0 10px 0 10px; border: 1px solid #aaa"> :''The following discussion is closed. <b style="color:red">Please do not modify it</b>. Subsequent comments should be made in a new section.'' ::With the unanimous support of 9 community members, this request is '''successful'''. Congratulations on being the first officially elected steward and welcome (back?) to the team! :) [[User:Globe|Globe]] ([[User talk:Globe|talk]]) 21:10, 21 April 2026 (UTC) ---- Hello! I'm Justarandomamerican, and I am filing a request for stewardship, because the board has abolished the staff role, and for staff members to keep their permissions, they must stand for election. I've been here since 2024, when the farm was founded. I hope the community trusts me. Thank you for your time! [[User:Justarandomamerican|Justarandomamerican]] ([[User talk:Justarandomamerican|talk]]) 21:10, 16 April 2026 (UTC) :<small> This candidate has signed an NDA with the WikiOasis Foundation, as is required for stewardship. [[User:Justarandomamerican|Justarandomamerican]] ([[User talk:Justarandomamerican|talk]]) 01:23, 17 April 2026 (UTC)</small> === Questions === In the interests of making this more of an interesting process than a formality, I have a few questions which more or less mirror to all candidates. Some I admit are bundled questions, feel free to answer to the extent applicable. # Based on your request, what do you currently do that requires Steward capabilities? # Do you believe you have made mistakes in your official capacity on this platform so far? If so, what did you do to improve from those mistakes? You could elaborate on just one if you like, or a couple. # What is your vision of what a steward is, and what they do for the community? # Two users appear in the CheckUser interface who both appear to be using Tor who are regular editors on a large wiki, which is also being attacked seemingly out of nowhere by an assailant who is using Tor and free VPNs. Is this a slam dunk connection, if your review of edits suggest their editing styles are similar (but no major stylistic tells)? Why/why not, and if not, what's the next step to find out? # How would you close a vote proposing a change in which seven people essentially say support and maybe a few words, nothing really in depth, and three people have articulated major concerns with the proposal at the level of detail of these questions? Would that process change if it was only one oppose like this to seven support, and if that oppose appeared just before you were going to close the RfC? Thank you, --'''[[User:Raidarr|raidarr]]''' '''('''[[User_talk:Raidarr|📡]]''')''' 22:45, 17 April 2026 (UTC) :Hello! Sorry I was unable to respond; I have other things going on. :# CheckUser and Oversight, definitely; I need those to help with abuse and help our wikis out. :# Oh yes, definitely. I have made mistakes, including unauthorized usage of Foundation funds. I have been working on impulse control, and will be in therapy for the foreseeable future. Thank you for asking. :# A steward is, fundamentally, a community representative. I represent the community, even though I might have some control over it, I shouldn't use it in an authoritarian manner. :# This does not seem to be a slam dunk connection. I would keep watching their contribs to find out. :# First one, would close as unsuccessful, it is not a consensus to have several support votes with no words, and a few major concerns articulated in detail. Second one, would relist. All opinions should have a chance to be considered, no matter how late they appeared. :[[User:Justarandomamerican|Justarandomamerican]] ([[User talk:Justarandomamerican|talk]]) 15:27, 20 April 2026 (UTC) A few questions targeted towards individual candidates across the process: # How do you see your history as president of the WikiOasis Foundation fits into this role, and the trust that the community will be placing in you that may not yet have been rebuilt? # What do you think that you would bring to the steward team that other candidates may not? # Can you discuss what your reasoning behind [https://italianbrainrot.wikioasis.org/wiki/Special:Log?logid=23008 this] was, as there were local administrators at the time who could've handled this apparent one off incident? # How do you feel that team discussion fits into the handling of appeals by banned and locked users, do you think that an appeal should be solely handled by one person without discussion? Best, --'''[[User:Zippy|zippy]]'''[[User talk:Zippy|bonzo]]''' ([[Special:Contributions/Zippy|c]] • [[Special:CentralAuth/Zippy|ca]]) 00:14, 18 April 2026 (UTC) :# Honestly, I see it fitting into this role somewhat. It was a major breach of trust, and I have worked on myself since then. I just hope it never happens again, with anybody. :# There are numerous experienced candidates, so nothing new there. I might just bring my track record of good behavior since the Foundation incident. :# That was clear and obvious vandalism, which can be handled by anyone with rights to delete, including GPs and GAs. :# I think there should be team discussion around appeals. One person handling it doesn't seem good, as they may be biased. :[[User:Justarandomamerican|Justarandomamerican]] ([[User talk:Justarandomamerican|talk]]) 15:32, 20 April 2026 (UTC) === Discussion === # {{support}}, has a clue, not a jerk --'''[[User:Zippy|zippy]]'''[[User talk:Zippy|bonzo]]''' ([[Special:Contributions/Zippy|c]] • [[Special:CentralAuth/Zippy|ca]]) 01:14, 17 April 2026 (UTC) #{{Support}} [[User:SleepingElephant2145|SleepingElephant2145]] ([[User talk:SleepingElephant2145|talk]]) 01:20, 17 April 2026 (UTC) # I have noticed Justarandomamerican around testwiki.wiki (where they serve as system admin/steward) and can {{support}} this request. <span style="font-family:Courier New;font-weight:bold;text-shadow:1px 1px 1px cyan">[[User:Tester|Tester]]</span> ([[User_talk:Tester|ᴛ]]•[[Special:Contributions/Tester|ᴄ]]) 01:40, 17 April 2026 (UTC) # {{Support|strongest}} <span style="background:#EFD8FD;color:Indigo;font-family:serif">~&nbsp;'''''[[User:Dream Indigo|<span style="color:Indigo">Dream Indigo</span>]]'''''&nbsp;[[User talk:Dream Indigo|<span style="color:Indigo">✩</span>]]</span> 01:49, 17 April 2026 (UTC) # No brainer {{support}}. [[User:Globe|Globe]] ([[User talk:Globe|talk]]) 01:53, 17 April 2026 (UTC) # Ex-Board Member and is trusted within the WikiOasis Volunteers. No brainer {{support}}. [[User:Fearless|Fearless]] ([[User talk:Fearless|talk]]) 10:22, 17 April 2026 (UTC) # {{Support}} --[[User:PinkPugPrincess|PinkPugPrincess]] ([[User talk:PinkPugPrincess|talk]]) 13:36, 17 April 2026 (UTC) # {{Support|Strongest}} [[User:AlPaD|AlPaD]] ([[User talk:AlPaD|talk]]) 14:52, 17 April 2026 (UTC) # {{Support}} No Concerns --[[User:Cocopuff2018|Cocopuff2018]] ([[User talk:Cocopuff2018|talk]]) 16:36, 17 April 2026 (UTC) ---- :''The above discussion is preserved as an archive. <b style="color:red">Please do not modify it</b>. Subsequent comments should be made in a new section.'' </div> qogasqzfdelv0ysbj7ir85jjiq1gr0x 739067 739065 2026-04-22T00:56:58Z AsteraBot 69554 Bot: removing archived sections 739067 wikitext text/x-wiki {{Autoarchive |archive=%(fullpage)/Archives/%(year) |ago=2m }} === Questions === In the interests of making this more of an interesting process than a formality, I have a few questions which more or less mirror to all candidates. Some I admit are bundled questions, feel free to answer to the extent applicable. # Based on your request, what do you currently do that requires Steward capabilities? # Do you believe you have made mistakes in your official capacity on this platform so far? If so, what did you do to improve from those mistakes? You could elaborate on just one if you like, or a couple. # What is your vision of what a steward is, and what they do for the community? # Two users appear in the CheckUser interface who both appear to be using Tor who are regular editors on a large wiki, which is also being attacked seemingly out of nowhere by an assailant who is using Tor and free VPNs. Is this a slam dunk connection, if your review of edits suggest their editing styles are similar (but no major stylistic tells)? Why/why not, and if not, what's the next step to find out? # How would you close a vote proposing a change in which seven people essentially say support and maybe a few words, nothing really in depth, and three people have articulated major concerns with the proposal at the level of detail of these questions? Would that process change if it was only one oppose like this to seven support, and if that oppose appeared just before you were going to close the RfC? Thank you, --'''[[User:Raidarr|raidarr]]''' '''('''[[User_talk:Raidarr|📡]]''')''' 22:45, 17 April 2026 (UTC) :Hello! Sorry I was unable to respond; I have other things going on. :# CheckUser and Oversight, definitely; I need those to help with abuse and help our wikis out. :# Oh yes, definitely. I have made mistakes, including unauthorized usage of Foundation funds. I have been working on impulse control, and will be in therapy for the foreseeable future. Thank you for asking. :# A steward is, fundamentally, a community representative. I represent the community, even though I might have some control over it, I shouldn't use it in an authoritarian manner. :# This does not seem to be a slam dunk connection. I would keep watching their contribs to find out. :# First one, would close as unsuccessful, it is not a consensus to have several support votes with no words, and a few major concerns articulated in detail. Second one, would relist. All opinions should have a chance to be considered, no matter how late they appeared. :[[User:Justarandomamerican|Justarandomamerican]] ([[User talk:Justarandomamerican|talk]]) 15:27, 20 April 2026 (UTC) A few questions targeted towards individual candidates across the process: # How do you see your history as president of the WikiOasis Foundation fits into this role, and the trust that the community will be placing in you that may not yet have been rebuilt? # What do you think that you would bring to the steward team that other candidates may not? # Can you discuss what your reasoning behind [https://italianbrainrot.wikioasis.org/wiki/Special:Log?logid=23008 this] was, as there were local administrators at the time who could've handled this apparent one off incident? # How do you feel that team discussion fits into the handling of appeals by banned and locked users, do you think that an appeal should be solely handled by one person without discussion? Best, --'''[[User:Zippy|zippy]]'''[[User talk:Zippy|bonzo]]''' ([[Special:Contributions/Zippy|c]] • [[Special:CentralAuth/Zippy|ca]]) 00:14, 18 April 2026 (UTC) :# Honestly, I see it fitting into this role somewhat. It was a major breach of trust, and I have worked on myself since then. I just hope it never happens again, with anybody. :# There are numerous experienced candidates, so nothing new there. I might just bring my track record of good behavior since the Foundation incident. :# That was clear and obvious vandalism, which can be handled by anyone with rights to delete, including GPs and GAs. :# I think there should be team discussion around appeals. One person handling it doesn't seem good, as they may be biased. :[[User:Justarandomamerican|Justarandomamerican]] ([[User talk:Justarandomamerican|talk]]) 15:32, 20 April 2026 (UTC) === Discussion === # {{support}}, has a clue, not a jerk --'''[[User:Zippy|zippy]]'''[[User talk:Zippy|bonzo]]''' ([[Special:Contributions/Zippy|c]] • [[Special:CentralAuth/Zippy|ca]]) 01:14, 17 April 2026 (UTC) #{{Support}} [[User:SleepingElephant2145|SleepingElephant2145]] ([[User talk:SleepingElephant2145|talk]]) 01:20, 17 April 2026 (UTC) # I have noticed Justarandomamerican around testwiki.wiki (where they serve as system admin/steward) and can {{support}} this request. <span style="font-family:Courier New;font-weight:bold;text-shadow:1px 1px 1px cyan">[[User:Tester|Tester]]</span> ([[User_talk:Tester|ᴛ]]•[[Special:Contributions/Tester|ᴄ]]) 01:40, 17 April 2026 (UTC) # {{Support|strongest}} <span style="background:#EFD8FD;color:Indigo;font-family:serif">~&nbsp;'''''[[User:Dream Indigo|<span style="color:Indigo">Dream Indigo</span>]]'''''&nbsp;[[User talk:Dream Indigo|<span style="color:Indigo">✩</span>]]</span> 01:49, 17 April 2026 (UTC) # No brainer {{support}}. [[User:Globe|Globe]] ([[User talk:Globe|talk]]) 01:53, 17 April 2026 (UTC) # Ex-Board Member and is trusted within the WikiOasis Volunteers. No brainer {{support}}. [[User:Fearless|Fearless]] ([[User talk:Fearless|talk]]) 10:22, 17 April 2026 (UTC) # {{Support}} --[[User:PinkPugPrincess|PinkPugPrincess]] ([[User talk:PinkPugPrincess|talk]]) 13:36, 17 April 2026 (UTC) # {{Support|Strongest}} [[User:AlPaD|AlPaD]] ([[User talk:AlPaD|talk]]) 14:52, 17 April 2026 (UTC) # {{Support}} No Concerns --[[User:Cocopuff2018|Cocopuff2018]] ([[User talk:Cocopuff2018|talk]]) 16:36, 17 April 2026 (UTC) ---- :''The above discussion is preserved as an archive. <b style="color:red">Please do not modify it</b>. Subsequent comments should be made in a new section.'' </div> kvmaed6ahkvknqgxhv92vzcwe5rtoil User talk:AsteraBot/Archives/2026 3 174965 739059 2026-04-22T00:36:03Z AsteraBot 69554 Bot: archiving sections 739059 wikitext text/x-wiki == Justarandomamerican (Steward)== <div class="boilerplate metadata discussion-archived" style="background-color: #F2F4FC; margin: 2em 0 0 0; padding: 0 10px 0 10px; border: 1px solid #aaa"> :''The following discussion is closed. <b style="color:red">Please do not modify it</b>. Subsequent comments should be made in a new section.'' ::With the unanimous support of 9 community members, this request is '''successful'''. Congratulations on being the first officially elected steward and welcome (back?) to the team! :) [[User:Globe|Globe]] ([[User talk:Globe|talk]]) 21:10, 21 April 2026 (UTC) ---- Hello! I'm Justarandomamerican, and I am filing a request for stewardship, because the board has abolished the staff role, and for staff members to keep their permissions, they must stand for election. I've been here since 2024, when the farm was founded. I hope the community trusts me. Thank you for your time! [[User:Justarandomamerican|Justarandomamerican]] ([[User talk:Justarandomamerican|talk]]) 21:10, 16 April 2026 (UTC) :<small> This candidate has signed an NDA with the WikiOasis Foundation, as is required for stewardship. [[User:Justarandomamerican|Justarandomamerican]] ([[User talk:Justarandomamerican|talk]]) 01:23, 17 April 2026 (UTC)</small> 5w3n0q97eh6hx1pcaxm25dkhodg5519 739062 739059 2026-04-22T00:49:10Z AsteraBot 69554 blanking 739062 wikitext text/x-wiki phoiac9h4m842xq45sp7s6u21eteeq1 739063 739062 2026-04-22T00:54:01Z AsteraBot 69554 Bot: archiving discussions 739063 wikitext text/x-wiki <div class="boilerplate metadata discussion-archived" style="background-color: #F2F4FC; margin: 2em 0 0 0; padding: 0 10px 0 10px; border: 1px solid #aaa"> :''The following discussion is closed. <b style="color:red">Please do not modify it</b>. Subsequent comments should be made in a new section.'' ::With the unanimous support of 9 community members, this request is '''successful'''. Congratulations on being the first officially elected steward and welcome (back?) to the team! :) [[User:Globe|Globe]] ([[User talk:Globe|talk]]) 21:10, 21 April 2026 (UTC) ---- Hello! I'm Justarandomamerican, and I am filing a request for stewardship, because the board has abolished the staff role, and for staff members to keep their permissions, they must stand for election. I've been here since 2024, when the farm was founded. I hope the community trusts me. Thank you for your time! [[User:Justarandomamerican|Justarandomamerican]] ([[User talk:Justarandomamerican|talk]]) 21:10, 16 April 2026 (UTC) :<small> This candidate has signed an NDA with the WikiOasis Foundation, as is required for stewardship. [[User:Justarandomamerican|Justarandomamerican]] ([[User talk:Justarandomamerican|talk]]) 01:23, 17 April 2026 (UTC)</small> === Questions === In the interests of making this more of an interesting process than a formality, I have a few questions which more or less mirror to all candidates. Some I admit are bundled questions, feel free to answer to the extent applicable. # Based on your request, what do you currently do that requires Steward capabilities? # Do you believe you have made mistakes in your official capacity on this platform so far? If so, what did you do to improve from those mistakes? You could elaborate on just one if you like, or a couple. # What is your vision of what a steward is, and what they do for the community? # Two users appear in the CheckUser interface who both appear to be using Tor who are regular editors on a large wiki, which is also being attacked seemingly out of nowhere by an assailant who is using Tor and free VPNs. Is this a slam dunk connection, if your review of edits suggest their editing styles are similar (but no major stylistic tells)? Why/why not, and if not, what's the next step to find out? # How would you close a vote proposing a change in which seven people essentially say support and maybe a few words, nothing really in depth, and three people have articulated major concerns with the proposal at the level of detail of these questions? Would that process change if it was only one oppose like this to seven support, and if that oppose appeared just before you were going to close the RfC? Thank you, --'''[[User:Raidarr|raidarr]]''' '''('''[[User_talk:Raidarr|📡]]''')''' 22:45, 17 April 2026 (UTC) :Hello! Sorry I was unable to respond; I have other things going on. :# CheckUser and Oversight, definitely; I need those to help with abuse and help our wikis out. :# Oh yes, definitely. I have made mistakes, including unauthorized usage of Foundation funds. I have been working on impulse control, and will be in therapy for the foreseeable future. Thank you for asking. :# A steward is, fundamentally, a community representative. I represent the community, even though I might have some control over it, I shouldn't use it in an authoritarian manner. :# This does not seem to be a slam dunk connection. I would keep watching their contribs to find out. :# First one, would close as unsuccessful, it is not a consensus to have several support votes with no words, and a few major concerns articulated in detail. Second one, would relist. All opinions should have a chance to be considered, no matter how late they appeared. :[[User:Justarandomamerican|Justarandomamerican]] ([[User talk:Justarandomamerican|talk]]) 15:27, 20 April 2026 (UTC) A few questions targeted towards individual candidates across the process: # How do you see your history as president of the WikiOasis Foundation fits into this role, and the trust that the community will be placing in you that may not yet have been rebuilt? # What do you think that you would bring to the steward team that other candidates may not? # Can you discuss what your reasoning behind [https://italianbrainrot.wikioasis.org/wiki/Special:Log?logid=23008 this] was, as there were local administrators at the time who could've handled this apparent one off incident? # How do you feel that team discussion fits into the handling of appeals by banned and locked users, do you think that an appeal should be solely handled by one person without discussion? Best, --'''[[User:Zippy|zippy]]'''[[User talk:Zippy|bonzo]]''' ([[Special:Contributions/Zippy|c]] • [[Special:CentralAuth/Zippy|ca]]) 00:14, 18 April 2026 (UTC) :# Honestly, I see it fitting into this role somewhat. It was a major breach of trust, and I have worked on myself since then. I just hope it never happens again, with anybody. :# There are numerous experienced candidates, so nothing new there. I might just bring my track record of good behavior since the Foundation incident. :# That was clear and obvious vandalism, which can be handled by anyone with rights to delete, including GPs and GAs. :# I think there should be team discussion around appeals. One person handling it doesn't seem good, as they may be biased. :[[User:Justarandomamerican|Justarandomamerican]] ([[User talk:Justarandomamerican|talk]]) 15:32, 20 April 2026 (UTC) === Discussion === # {{support}}, has a clue, not a jerk --'''[[User:Zippy|zippy]]'''[[User talk:Zippy|bonzo]]''' ([[Special:Contributions/Zippy|c]] • [[Special:CentralAuth/Zippy|ca]]) 01:14, 17 April 2026 (UTC) #{{Support}} [[User:SleepingElephant2145|SleepingElephant2145]] ([[User talk:SleepingElephant2145|talk]]) 01:20, 17 April 2026 (UTC) # I have noticed Justarandomamerican around testwiki.wiki (where they serve as system admin/steward) and can {{support}} this request. <span style="font-family:Courier New;font-weight:bold;text-shadow:1px 1px 1px cyan">[[User:Tester|Tester]]</span> ([[User_talk:Tester|ᴛ]]•[[Special:Contributions/Tester|ᴄ]]) 01:40, 17 April 2026 (UTC) # {{Support|strongest}} <span style="background:#EFD8FD;color:Indigo;font-family:serif">~&nbsp;'''''[[User:Dream Indigo|<span style="color:Indigo">Dream Indigo</span>]]'''''&nbsp;[[User talk:Dream Indigo|<span style="color:Indigo">✩</span>]]</span> 01:49, 17 April 2026 (UTC) # No brainer {{support}}. [[User:Globe|Globe]] ([[User talk:Globe|talk]]) 01:53, 17 April 2026 (UTC) # Ex-Board Member and is trusted within the WikiOasis Volunteers. No brainer {{support}}. [[User:Fearless|Fearless]] ([[User talk:Fearless|talk]]) 10:22, 17 April 2026 (UTC) # {{Support}} --[[User:PinkPugPrincess|PinkPugPrincess]] ([[User talk:PinkPugPrincess|talk]]) 13:36, 17 April 2026 (UTC) # {{Support|Strongest}} [[User:AlPaD|AlPaD]] ([[User talk:AlPaD|talk]]) 14:52, 17 April 2026 (UTC) # {{Support}} No Concerns --[[User:Cocopuff2018|Cocopuff2018]] ([[User talk:Cocopuff2018|talk]]) 16:36, 17 April 2026 (UTC) ---- :''The above discussion is preserved as an archive. <b style="color:red">Please do not modify it</b>. Subsequent comments should be made in a new section.'' </div> 8lej643z0xe21spnp3hs40wko87u4qo 739066 739063 2026-04-22T00:56:58Z AsteraBot 69554 Bot: archiving discussions 739066 wikitext text/x-wiki <div class="boilerplate metadata discussion-archived" style="background-color: #F2F4FC; margin: 2em 0 0 0; padding: 0 10px 0 10px; border: 1px solid #aaa"> :''The following discussion is closed. <b style="color:red">Please do not modify it</b>. Subsequent comments should be made in a new section.'' ::With the unanimous support of 9 community members, this request is '''successful'''. Congratulations on being the first officially elected steward and welcome (back?) to the team! :) [[User:Globe|Globe]] ([[User talk:Globe|talk]]) 21:10, 21 April 2026 (UTC) ---- Hello! I'm Justarandomamerican, and I am filing a request for stewardship, because the board has abolished the staff role, and for staff members to keep their permissions, they must stand for election. I've been here since 2024, when the farm was founded. I hope the community trusts me. Thank you for your time! [[User:Justarandomamerican|Justarandomamerican]] ([[User talk:Justarandomamerican|talk]]) 21:10, 16 April 2026 (UTC) :<small> This candidate has signed an NDA with the WikiOasis Foundation, as is required for stewardship. [[User:Justarandomamerican|Justarandomamerican]] ([[User talk:Justarandomamerican|talk]]) 01:23, 17 April 2026 (UTC)</small> === Questions === In the interests of making this more of an interesting process than a formality, I have a few questions which more or less mirror to all candidates. Some I admit are bundled questions, feel free to answer to the extent applicable. # Based on your request, what do you currently do that requires Steward capabilities? # Do you believe you have made mistakes in your official capacity on this platform so far? If so, what did you do to improve from those mistakes? You could elaborate on just one if you like, or a couple. # What is your vision of what a steward is, and what they do for the community? # Two users appear in the CheckUser interface who both appear to be using Tor who are regular editors on a large wiki, which is also being attacked seemingly out of nowhere by an assailant who is using Tor and free VPNs. Is this a slam dunk connection, if your review of edits suggest their editing styles are similar (but no major stylistic tells)? Why/why not, and if not, what's the next step to find out? # How would you close a vote proposing a change in which seven people essentially say support and maybe a few words, nothing really in depth, and three people have articulated major concerns with the proposal at the level of detail of these questions? Would that process change if it was only one oppose like this to seven support, and if that oppose appeared just before you were going to close the RfC? Thank you, --'''[[User:Raidarr|raidarr]]''' '''('''[[User_talk:Raidarr|📡]]''')''' 22:45, 17 April 2026 (UTC) :Hello! Sorry I was unable to respond; I have other things going on. :# CheckUser and Oversight, definitely; I need those to help with abuse and help our wikis out. :# Oh yes, definitely. I have made mistakes, including unauthorized usage of Foundation funds. I have been working on impulse control, and will be in therapy for the foreseeable future. Thank you for asking. :# A steward is, fundamentally, a community representative. I represent the community, even though I might have some control over it, I shouldn't use it in an authoritarian manner. :# This does not seem to be a slam dunk connection. I would keep watching their contribs to find out. :# First one, would close as unsuccessful, it is not a consensus to have several support votes with no words, and a few major concerns articulated in detail. Second one, would relist. All opinions should have a chance to be considered, no matter how late they appeared. :[[User:Justarandomamerican|Justarandomamerican]] ([[User talk:Justarandomamerican|talk]]) 15:27, 20 April 2026 (UTC) A few questions targeted towards individual candidates across the process: # How do you see your history as president of the WikiOasis Foundation fits into this role, and the trust that the community will be placing in you that may not yet have been rebuilt? # What do you think that you would bring to the steward team that other candidates may not? # Can you discuss what your reasoning behind [https://italianbrainrot.wikioasis.org/wiki/Special:Log?logid=23008 this] was, as there were local administrators at the time who could've handled this apparent one off incident? # How do you feel that team discussion fits into the handling of appeals by banned and locked users, do you think that an appeal should be solely handled by one person without discussion? Best, --'''[[User:Zippy|zippy]]'''[[User talk:Zippy|bonzo]]''' ([[Special:Contributions/Zippy|c]] • [[Special:CentralAuth/Zippy|ca]]) 00:14, 18 April 2026 (UTC) :# Honestly, I see it fitting into this role somewhat. It was a major breach of trust, and I have worked on myself since then. I just hope it never happens again, with anybody. :# There are numerous experienced candidates, so nothing new there. I might just bring my track record of good behavior since the Foundation incident. :# That was clear and obvious vandalism, which can be handled by anyone with rights to delete, including GPs and GAs. :# I think there should be team discussion around appeals. One person handling it doesn't seem good, as they may be biased. :[[User:Justarandomamerican|Justarandomamerican]] ([[User talk:Justarandomamerican|talk]]) 15:32, 20 April 2026 (UTC) === Discussion === # {{support}}, has a clue, not a jerk --'''[[User:Zippy|zippy]]'''[[User talk:Zippy|bonzo]]''' ([[Special:Contributions/Zippy|c]] • [[Special:CentralAuth/Zippy|ca]]) 01:14, 17 April 2026 (UTC) #{{Support}} [[User:SleepingElephant2145|SleepingElephant2145]] ([[User talk:SleepingElephant2145|talk]]) 01:20, 17 April 2026 (UTC) # I have noticed Justarandomamerican around testwiki.wiki (where they serve as system admin/steward) and can {{support}} this request. <span style="font-family:Courier New;font-weight:bold;text-shadow:1px 1px 1px cyan">[[User:Tester|Tester]]</span> ([[User_talk:Tester|ᴛ]]•[[Special:Contributions/Tester|ᴄ]]) 01:40, 17 April 2026 (UTC) # {{Support|strongest}} <span style="background:#EFD8FD;color:Indigo;font-family:serif">~&nbsp;'''''[[User:Dream Indigo|<span style="color:Indigo">Dream Indigo</span>]]'''''&nbsp;[[User talk:Dream Indigo|<span style="color:Indigo">✩</span>]]</span> 01:49, 17 April 2026 (UTC) # No brainer {{support}}. [[User:Globe|Globe]] ([[User talk:Globe|talk]]) 01:53, 17 April 2026 (UTC) # Ex-Board Member and is trusted within the WikiOasis Volunteers. No brainer {{support}}. [[User:Fearless|Fearless]] ([[User talk:Fearless|talk]]) 10:22, 17 April 2026 (UTC) # {{Support}} --[[User:PinkPugPrincess|PinkPugPrincess]] ([[User talk:PinkPugPrincess|talk]]) 13:36, 17 April 2026 (UTC) # {{Support|Strongest}} [[User:AlPaD|AlPaD]] ([[User talk:AlPaD|talk]]) 14:52, 17 April 2026 (UTC) # {{Support}} No Concerns --[[User:Cocopuff2018|Cocopuff2018]] ([[User talk:Cocopuff2018|talk]]) 16:36, 17 April 2026 (UTC) ---- :''The above discussion is preserved as an archive. <b style="color:red">Please do not modify it</b>. Subsequent comments should be made in a new section.'' </div> == Justarandomamerican (Steward)== <div class="boilerplate metadata discussion-archived" style="background-color: #F2F4FC; margin: 2em 0 0 0; padding: 0 10px 0 10px; border: 1px solid #aaa"> :''The following discussion is closed. <b style="color:red">Please do not modify it</b>. Subsequent comments should be made in a new section.'' ::With the unanimous support of 9 community members, this request is '''successful'''. Congratulations on being the first officially elected steward and welcome (back?) to the team! :) [[User:Globe|Globe]] ([[User talk:Globe|talk]]) 21:10, 21 April 2026 (UTC) ---- Hello! I'm Justarandomamerican, and I am filing a request for stewardship, because the board has abolished the staff role, and for staff members to keep their permissions, they must stand for election. I've been here since 2024, when the farm was founded. I hope the community trusts me. Thank you for your time! [[User:Justarandomamerican|Justarandomamerican]] ([[User talk:Justarandomamerican|talk]]) 21:10, 16 April 2026 (UTC) :<small> This candidate has signed an NDA with the WikiOasis Foundation, as is required for stewardship. [[User:Justarandomamerican|Justarandomamerican]] ([[User talk:Justarandomamerican|talk]]) 01:23, 17 April 2026 (UTC)</small> haajgmm8ovdrxft35dtroda4rco1ijb