Module:WP
Appearance
![]() | This module depends on the following other modules: |
Implements {{WP}}
require('Module:No globals');
local getArgs = require ('Module:Arguments').getArgs;
local mRedirect = require ('Module:Redirect')
--[[--------------------------< E S C A P E _ L U A _ M A G I C _ C H A R S >----------------------------------
Returns a string where all of lua's magic characters have been escaped. This is important because functions like
string.gsub() treat their pattern and replace strings as patterns, not literal strings.
]]
local function escape_lua_magic_chars (argument)
argument = argument:gsub("%%", "%%%%"); -- replace % with %%
argument = argument:gsub("([%^%$%(%)%.%[%]%*%+%-%?])", "%%%1"); -- replace all other lua magic pattern characters
return argument;
end
--[[--------------------------< E R R >------------------------------------------------------------------------
returns formatted error message that is less strident than error() or standard MediaWiki error messages
TODO: add link to template page for help text
]]
local function err (error_msg)
return '<span class="error" style="font-size:100%">' .. error_msg .. '</span>'; -- tamer, less strident error messages
end
-- Get a redirect target (or nil if not a redirect) without using the expensive title object property .isRedirect
local function getRedirectTarget(titleObject)
local content = titleObject:getContent()
if not content then return nil end
return mRedirect.getTargetFromText(content)
end
-- Get a page's content, following redirects, and processing file description pages for files.
-- Also returns the page name, or the target page name if a redirect was followed, or false if no page found
local function getContent(page, frame)
local title = mw.title.new(page) -- Read description page (for :File:Foo rather than File:Foo)
if not title then return false, false end
local redir = getRedirectTarget(title)
if redir then title = mw.title.new(redir) end
return title:getContent(), redir or title.prefixedText
end
--[=[-------------------------< W I K I L I N K _ S T R I P >--------------------------------------------------
Wikilink markup does not belong in an anchor id and can / does confuse the code that parses apart citation and
harvc templates so here we remove any wiki markup:
[[link|label]] -> label
[[link]] -> link
]=]
local function wikilink_strip(text)
for wikilink in text:gmatch('%[%b[]%]') do -- get a wikilink
text = text:gsub('%[%b[]%]', '__57r1P__', 1) -- install a marker
if wikilink:match ('^%[%[%s*[Ff]ile:') or wikilink:match ('^%[%[%s*[Ii]mage:') then -- if this wikilink is an image
wikilink = '[IMAGE]'; -- can't display it in a tooltip so use a word; TODO: parse out alt text or caption? worth the effort?
elseif wikilink:match('%[%[.-|(.-)%]%]') then
wikilink = wikilink:match('%[%[.-|(.-)%]%]') -- extract label from complex [[link|label]] wikilink
else
wikilink = wikilink:match('%[%[(.-)%]%]') -- extract link from simple [[link]] wikilinks
end
wikilink = escape_lua_magic_chars(wikilink) -- in case there are lua magic characters in wikilink
text = text:gsub('__57r1P__', wikilink, 1) -- replace the marker with the appropriate text
end
return text
end
--[[--------------------------< N U T S H E L L _ T E X T _ G E T >--------------------------------------------
gets text from {{nutshell}} or redirect in target pagename; frame included as argument here so that this function
has access to frame:preprocess()
pagename is shortcut name with WP: prefix
]]
local function nutshell_text_get (pagename, frame)
local content, normalisedPagename = getContent(pagename)
if not normalisedPagename then
return nil, 'No title for page name ' .. pagename;
end
if content then -- why do we care if page is a stub?
local isStub = mw.ustring.find(content, "%s*{{[^{|}]*%-[Ss]tub%s*}}")
if isStub then content = nil end
end
if not content then
return nil, 'Cannot read a valid page: page name is ' .. pagename;
end
local templatePatterns = {
"{{%s*[Nn]utshell%s*|",
"{{%s*[Pp]olicy in a nutshell%s*|",
"{{%s*[Pp]olicy proposal in a nutshell%s*|",
"{{%s*[Ii]n a nutshell%s*|",
"{{%s*[Ii]nanutshell%s*|",
"{{%s*[Gg]uideline in a nutshell%s*|",
"{{%s*[Gg]uideline one liner%s*|",
"{{%s*[Nn]aming convention in a nutshell%s*|",
"{{%s*[Nn]utshell2%s*|",
"{{%s*[Pp]roposal in a nutshell%s*|",
"{{%s*[Ee]ssay in a nutshell%s*|"
}
local nutshell
for i, pattern in ipairs (templatePatterns) do
local pos = mw.ustring.find (content, pattern)
if pos then
nutshell = mw.ustring.match (content, '%b{}', pos)
break
end
end
if not nutshell then -- nil when there is no recognized nutshell template
-- return nil, 'Page has no nutshell text: ' .. pagename; -- template not text
return; -- this is not an error
end
-- begin template disassembly - order is important here - rare case where |title= holds a template
nutshell = nutshell:gsub ('^{{[%w%s]*|', ''):gsub ('}}$', ''); -- remove opening {{ and template name then remove closing }}
for t in nutshell:gmatch('%b{}') do -- get an embedded template
nutshell = nutshell:gsub('%b{}', '__57r1P__', 1) -- install a marker
local replacement = frame:preprocess (t); -- get the template's rendering
replacement = escape_lua_magic_chars(replacement); -- in case there are lua magic characters in replacement
nutshell = nutshell:gsub('__57r1P__', replacement, 1) -- replace the marker with the appropriate text
end
nutshell = wikilink_strip (nutshell); -- remove wikilinks
local title = nutshell:match ('|%s*title%s*=%s*([^|]+)') or ''; -- get title text or an empty string
title = mw.text.trim (title); -- remove extraneous leading / trailing whitespace
if '' == title then
title = 'This page'; -- use default when |title= missing or empty
end
title = title .. ' in a nutshell: '; -- finish the title; TODO: use a cleaned-up normalisedPagename instead?
nutshell = nutshell:gsub ('|%s*title%s*=%s*[^|]*', ''); -- remove title parameter and value; TODO: these two can be made one?
nutshell = nutshell:gsub ('|%s*shortcut%d*%s*[^|]*', ''); -- remove all shortcut parameters and their values
local c; -- holds the tally of pipes replaced
nutshell, c = nutshell:gsub ('%s*|%s*', ' *'); -- replace pipes and get a tally
if 0 < c then
nutshell = '*' .. nutshell; -- if any pipes were replaced, prefix with a splat
end
nutshell = nutshell:gsub ('"', "'"):gsub ('%b<>', ''); -- convert double quotes to single quotes then remove html-like tags
-- end template disassembly
return '' ~= nutshell and (title .. nutshell) or ''; -- when nutshell not an empty string, concat with title and done; empty string else
end
--[[--------------------------< I N V O K E >------------------------------------------------------------------
template entry point
{{#invoke:Nutshell|invoke|<pagename>}} where <pagename> is shortcut name without namespace prefix; BOLD not WP:BOLD
TODOs:
better module name
better function name
accept <pagename> with namespace prefix and strip the prefix if it is WP:
what about {{nutshell}} used in other namespaces? allowed? not allowed?
remove commented-out code
what about other namespaces?
MOS:SELFREF aka WP:SELF
MOS:LIST aka nothing
or long names?
WP:Chinese interlanguage links aka nothing
]]
local function invoke(frame)
local args = getArgs (frame); -- get a table of arguments
local out = {}
local pagename = args[1]; -- TODO: error check this; no point in continuing without properly formed pagename
if not pagename or '' == pagename then
return err ('No page name given');
end
if pagename:match ('%u+:(%a+)') then
pagename = pagename:gsub ('%u+:(%a+)', 'WP:%1'); -- replace whatever namespace is included and rewrite to WP: namespace
else
pagename = 'WP:' .. pagename; -- add WP: namespace
end
local nutshell, error_msg = nutshell_text_get (pagename, frame); -- pass frame so that nutshell_text_get() has access to frame:preprocess()
if error_msg then
return err (error_msg);
end
table.insert (out, '[['); -- open wikilink
table.insert (out, pagename); -- add pagename
if nutshell then
table.insert (out, '|<span title="'); -- pipe, then start the opening span
table.insert (out, nutshell); -- add nutshell text
table.insert (out, '" class="rt-commentedText" style="border-bottom:1px dotted">'); --finish the opening span
table.insert (out, pagename); -- add pagename
table.insert (out, '</span>'); -- close the span
end
table.insert (out, ']]'); -- close the wikilink
return table.concat (out); -- concatenate and done
end
--[[--------------------------< E X P O R T E D F U N C T I O N S >------------------------------------------
]]
return {
invoke = invoke, -- TODO: better name required
}