48,403
edits
(Created page with "local export = {} local string_utilities_module = "Module:string utilities" local concat = table.concat local find = string.find local format = string.format local getmetatable = getmetatable local get_current_section -- Defined below. local get_pagetype -- Defined below. local gsub = string.gsub local insert = table.insert local is_internal_title -- Defined below. local is_title -- Defined below. local lower = string.lower local match = string.match local new_title =...") |
No edit summary |
||
| (3 intermediate revisions by 2 users not shown) | |||
| Line 7: | Line 7: | ||
local format = string.format | local format = string.format | ||
local getmetatable = getmetatable | local getmetatable = getmetatable | ||
local get_current_section -- | local get_current_section -- defined below | ||
local get_pagetype -- | local get_namespace_shortcut -- defined below | ||
local get_pagetype -- defined below | |||
local gsub = string.gsub | local gsub = string.gsub | ||
local insert = table.insert | local insert = table.insert | ||
local is_internal_title -- | local is_internal_title -- defined below | ||
local is_title -- | local is_title -- defined below | ||
local lower = string.lower | local lower = string.lower | ||
local match = string.match | local match = string.match | ||
| Line 43: | Line 44: | ||
--[==[ | --[==[ | ||
Loaders for objects, which load data (or some other object) into some variable, which can then be accessed as "foo or get_foo()", where the function get_foo sets the object to "foo" and then returns it. This ensures they are only loaded when needed, and avoids the need to check for the existence of the object each time, since once "foo" has been set, "get_foo" will not be called again.]==] | Loaders for objects, which load data (or some other object) into some variable, which can then be accessed as "foo or get_foo()", where the function get_foo sets the object to "foo" and then returns it. This ensures they are only loaded when needed, and avoids the need to check for the existence of the object each time, since once "foo" has been set, "get_foo" will not be called again.]==] | ||
local current_frame | |||
local function get_current_frame() | |||
current_frame, get_current_frame = mw.getCurrentFrame(), nil | |||
return current_frame | |||
end | |||
local parent_frame | |||
local function get_parent_frame() | |||
parent_frame, get_parent_frame = (current_frame or get_current_frame()):getParent(), nil | |||
return parent_frame | |||
end | |||
local namespace_shortcuts | local namespace_shortcuts | ||
local function get_namespace_shortcuts() | local function get_namespace_shortcuts() | ||
| Line 55: | Line 68: | ||
}, nil | }, nil | ||
return namespace_shortcuts | return namespace_shortcuts | ||
end | |||
do | |||
local transcluded | |||
--[==[ | |||
Returns {true} if the current {{tl|#invoke:}} is being transcluded, or {false} if not. If the current {{tl|#invoke:}} is part of a template, for instance, this template will therefore return {true}. | |||
Note that if a template containing an {{tl|#invoke:}} is used on its own page (e.g. to display a demonstration), this function is still able to detect that this is transclusion. This is an improvement over the other method for detecting transclusion, which is to check the parent frame title against the current page title, which fails to detect transclusion in that instance.]==] | |||
function export.is_transcluded() | |||
if transcluded == nil then | |||
transcluded = (parent_frame or get_parent_frame()) and parent_frame:preprocess("<includeonly>1</includeonly>") == "1" or false | |||
end | |||
return transcluded | |||
end | |||
end | |||
do | |||
local preview | |||
--[==[ | |||
Returns {true} if the page is currently being viewed in preview, or {false} if not.]==] | |||
function export.is_preview() | |||
if preview == nil then | |||
preview = (current_frame or get_current_frame()):preprocess("{{REVISIONID}}") == "" | |||
end | |||
return preview | |||
end | |||
end | end | ||
--[==[ | --[==[ | ||
Returns true if the input is a title object, or false if not. This therefore '''includes''' external title objects (i.e. those for pages on other wikis), such as [[w:Example]], unlike `is_internal_title` below.]==] | Returns {true} if the input is a title object, or {false} if not. This therefore '''includes''' external title objects (i.e. those for pages on other wikis), such as [[w:Example]], unlike `is_internal_title` below.]==] | ||
function export.is_title(val) | function export.is_title(val) | ||
if not (val and type(val) == "table") then | if not (val and type(val) == "table") then | ||
| Line 76: | Line 115: | ||
--[==[ | --[==[ | ||
Returns true if the input is an internal title object, | Returns {true} if the input is an internal title object, or {false} if not. An internal title object is a title object for a page on this wiki, such as [[example]]. This therefore '''excludes''' external title objects (i.e. those for pages on other wikis), such as [[w:Example]], unlike `is_title` above.]==] | ||
function export.is_internal_title(title) | function export.is_internal_title(title) | ||
-- Note: Mainspace titles starting with "#" should be invalid, but a bug in mw.title.new and mw.title.makeTitle means a title object is returned that has the empty string for prefixedText, so they need to be filtered out. | -- Note: Mainspace titles starting with "#" should be invalid, but a bug in mw.title.new and mw.title.makeTitle means a title object is returned that has the empty string for prefixedText, so they need to be filtered out. | ||
| Line 84: | Line 123: | ||
--[==[ | --[==[ | ||
Returns true if the input is a valid link target, or false if not. This therefore '''includes''' link targets to other wikis, such as [[w:Example]], unlike `is_valid_page_name` below.]==] | Returns {true} if the input string is a valid link target, or {false} if not. This therefore '''includes''' link targets to other wikis, such as [[w:Example]], unlike `is_valid_page_name` below.]==] | ||
function export.is_valid_link_target(target) | function export.is_valid_link_target(target) | ||
local target_type = type(target) | local target_type = type(target) | ||
| Line 94: | Line 133: | ||
--[==[ | --[==[ | ||
Returns true if the input is a valid page name | Returns {true} if the input string is a valid page name on this wiki, or {false} if not. This therefore '''excludes''' page names on other wikis, such as [[w:Example]], unlike `is_valid_link_target` above.]==] | ||
function export.is_valid_page_name(name) | function export.is_valid_page_name(name) | ||
local name_type = type(name) | local name_type = type(name) | ||
| Line 101: | Line 140: | ||
end | end | ||
error(format("bad argument #1 to 'is_valid_page_name' (string expected, got %s)", name_type), 2) | error(format("bad argument #1 to 'is_valid_page_name' (string expected, got %s)", name_type), 2) | ||
end | |||
--[==[ | |||
Given a title object, returns a full link target which will always unambiguously link to it. | |||
For instance, the input {"foo"} (for the page [[foo]]) returns {":foo"}, as a leading colon always refers to mainspace, even when other namespaces might be assumed (e.g. when transcluding using `{{ }}` syntax). | |||
If `shortcut` is set, then the returned target will use the namespace shortcut, if any; for example, the title for `Template:foo` would return {"T:foo"} instead of {"Template:foo"}.]==] | |||
function export.get_link_target(title, shortcut) | |||
if not is_title(title) then | |||
error(format("bad argument #1 to 'is_valid_link_target' (title object expected, got %s)", type(title))) | |||
elseif title.interwiki ~= "" then | |||
return title.fullText | |||
elseif shortcut then | |||
local fragment = title.fragment | |||
if fragment == "" then | |||
return get_namespace_shortcut(title) .. ":" .. title.text | |||
end | |||
return get_namespace_shortcut(title) .. ":" .. title.text .. "#" .. fragment | |||
elseif title.namespace == 0 then | |||
return ":" .. title.fullText | |||
end | |||
return title.fullText | |||
end | end | ||
| Line 147: | Line 209: | ||
--[==[ | --[==[ | ||
Returns the page type of | Returns the page type of the input title object in a format which can be used in running text.]==] | ||
function export.get_pagetype(title) | function export.get_pagetype(title) | ||
if not is_internal_title(title) then | if not is_internal_title(title) then | ||
error(mw.dumpObject(title.fullText) .. " is not a valid page name.") | error(mw.dumpObject(title.fullText) .. " is not a valid page name.") | ||
end | end | ||
-- If possibly a documentation page, get the | -- If possibly a documentation page, get the base title and set the | ||
-- `documentation` flag. | -- `documentation` flag. | ||
local content_model, text, documentation = title.contentModel | local content_model, text, documentation = title.contentModel | ||
if content_model == "wikitext" then | if content_model == "wikitext" then | ||
text = title.text | text = title.text | ||
if | if title.isSubpage and title.subpageText == "documentation" then | ||
local | local base_title = title.basePageTitle | ||
if | if base_title then | ||
title | title, content_model, text, documentation = base_title, base_title.contentModel, base_title.text, true | ||
end | end | ||
end | end | ||
| Line 218: | Line 279: | ||
--[==[ | --[==[ | ||
Returns true if the title object is for a content page, | Returns {true} if the input title object is for a content page, or {false} if not. A content page is a page that is considered part of the dictionary itself, and excludes pages for discussion, administration, maintenance etc.]==] | ||
function export.is_content_page(title) | function export.is_content_page(title) | ||
if not is_internal_title(title) then | if not is_internal_title(title) then | ||
| Line 224: | Line 285: | ||
end | end | ||
local ns = title.namespace | local ns = title.namespace | ||
-- (main), | -- (main), Contionary | ||
return (ns == 0 or ns == | return (ns == 0 or ns == 120) and | ||
title.contentModel == "wikitext" | title.contentModel == "wikitext" | ||
end | end | ||
--[==[ | --[==[ | ||
Returns true if the title object is for a documentation page, or false if not.]==] | Returns {true} if the input title object is for a documentation page, or {false} if not.]==] | ||
function export.is_documentation(title) | function export.is_documentation(title) | ||
return match(get_pagetype(title), "%f[%w]documentation%f[%W]") and true or false | return match(get_pagetype(title), "%f[%w]documentation%f[%W]") and true or false | ||
| Line 236: | Line 297: | ||
--[==[ | --[==[ | ||
Returns true if the title object is for a sandbox, or false if not. | Returns {true} if the input title object is for a sandbox, or {false} if not. | ||
By default, sandbox documentation pages are excluded, but this can be overridden with the `include_documentation` parameter.]==] | By default, sandbox documentation pages are excluded, but this can be overridden with the `include_documentation` parameter.]==] | ||
| Line 248: | Line 309: | ||
--[==[ | --[==[ | ||
Returns true if the title object is for a testcase page, or false if not. | Returns {true} if the input title object is for a testcase page, or {false} if not. | ||
By default, testcase documentation pages are excluded, but this can be overridden with the `include_documentation` parameter.]==] | By default, testcase documentation pages are excluded, but this can be overridden with the `include_documentation` parameter.]==] | ||
| Line 260: | Line 321: | ||
--[==[ | --[==[ | ||
Returns the namespace shortcut for | Returns the namespace shortcut for the input title object, or else the namespace text. For example, a `Template:` title returns {"T"}, a `Module:` title returns {"MOD"}, and a `User:` title returns {"User"}.]==] | ||
function export.get_namespace_shortcut(title) | function export.get_namespace_shortcut(title) | ||
return (namespace_shortcuts or get_namespace_shortcuts())[title.namespace] or title.nsText | return (namespace_shortcuts or get_namespace_shortcuts())[title.namespace] or title.nsText | ||
end | end | ||
get_namespace_shortcut = export.get_namespace_shortcut | |||
do | do | ||
| Line 355: | Line 417: | ||
do | do | ||
local current_section | local current_section | ||
--[==[ | --[==[ | ||
A function which returns the number of the page section which contains the current {#invoke}.]==] | A function which returns the number of the page section which contains the current {#invoke}.]==] | ||
function export.get_current_section() | function export.get_current_section() | ||
if current_section then | if current_section ~= nil then | ||
return current_section | return current_section | ||
end | end | ||
local | local extension_tag = (current_frame or get_current_frame()).extensionTag | ||
-- We determine the section via the heading strip marker count, since they're numbered sequentially, but the only way to do this is to generate a fake heading via frame:preprocess(). The native parser assigns each heading a unique marker, but frame:preprocess() will return copies of older markers if the heading is identical to one further up the page, so the fake heading has to be unique to the page. The best way to do this is to feed it a heading containing a nowiki marker (which we will need later), since those are always unique. | -- We determine the section via the heading strip marker count, since they're numbered sequentially, but the only way to do this is to generate a fake heading via frame:preprocess(). The native parser assigns each heading a unique marker, but frame:preprocess() will return copies of older markers if the heading is identical to one further up the page, so the fake heading has to be unique to the page. The best way to do this is to feed it a heading containing a nowiki marker (which we will need later), since those are always unique. | ||
local nowiki_marker = extension_tag( | local nowiki_marker = extension_tag(current_frame, "nowiki") | ||
-- Note: heading strip markers have a different syntax to the ones used for tags. | -- Note: heading strip markers have a different syntax to the ones used for tags. | ||
local h = tonumber(match( | local h = tonumber(match( | ||
current_frame:preprocess("=" .. nowiki_marker .. "="), | |||
"\127'\"`UNIQ%-%-h%-(%d+)%-%-QINU`\"'\127" | "\127'\"`UNIQ%-%-h%-(%d+)%-%-QINU`\"'\127" | ||
)) | )) | ||
| Line 388: | Line 448: | ||
end | end | ||
offset = offset and (offset + 1) or 0 | offset = offset and (offset + 1) or 0 | ||
extension_tag( | extension_tag(current_frame, "nowiki", "HEADING\1" .. offset) | ||
current_section = h - offset | current_section = h - offset | ||
return current_section | return current_section | ||