Line 1: |
Line 1: |
| --[==[ This module is a Lua implementation of the old {{Portal}} template. As of August 2013 it is used on nearly 5,000,000 articles. | | --[==[ This module is a Lua implementation of the old {{Portal}} template. As of August 2013 it is used on nearly 5,000,000 articles. |
− | -- Please take care when updating it! It outputs two functions: p.portal, which generates a table of portals, and p.image, which | + | -- Please take care when updating it! It outputs two functions: p.portal, which generates a list of portals, and p.image, which |
| -- produces the image name for an individual portal. | | -- produces the image name for an individual portal. |
| | | |
Line 70: |
Line 70: |
| local function getImageName(s) | | local function getImageName(s) |
| -- Gets the image name for a given string. | | -- Gets the image name for a given string. |
| + | local default = 'Portal-puzzle.svg|link=|alt=' |
| if type(s) ~= 'string' or #s < 1 then | | if type(s) ~= 'string' or #s < 1 then |
− | return 'Portal-puzzle.svg' | + | return default |
| end | | end |
| s = mw.ustring.lower(s) | | s = mw.ustring.lower(s) |
− | return matchImagePage(s) or matchImagePage(getAlias(s)) or 'Portal-puzzle.svg' | + | return matchImagePage(s) or matchImagePage(getAlias(s)) or default |
| + | end |
| + | |
| + | local function checkPortalExists(portal) |
| + | return not (mw.title.makeTitle(100, portal).id == 0) |
| end | | end |
| | | |
Line 80: |
Line 85: |
| -- This function builds the portal box used by the {{portal}} template. | | -- This function builds the portal box used by the {{portal}} template. |
| local root = mw.html.create('div') | | local root = mw.html.create('div') |
− | :addClass('noprint portal') | + | :attr('role', 'navigation') |
| + | :attr('aria-label', 'Portals') |
| + | :addClass('noprint portal plainlist') |
| :addClass(args.left and 'tleft' or 'tright') | | :addClass(args.left and 'tleft' or 'tright') |
| + | :css('margin', args.margin or (args.left == 'yes' and '0.5em 1em 0.5em 0') or '0.5em 0 0.5em 1em') |
| :css('border', 'solid #aaa 1px') | | :css('border', 'solid #aaa 1px') |
− | :css('margin', args.margin or (args.left == 'yes' and '0.5em 1em 0.5em 0') or '0.5em 0 0.5em 1em')
| |
| :newline() | | :newline() |
| | | |
− | -- Start the table. This corresponds to the start of the wikitext table in the old [[Template:Portal]]. | + | -- If no portals have been specified, display an error and add the page to a tracking category. |
− | local tableroot = root:tag('table') | + | if not portals[1] then |
| + | root:wikitext('<strong class="error">No portals specified: please specify at least one portal</strong>[[Category:Portal templates without a parameter]]') |
| + | return tostring(root) |
| + | end |
| + | |
| + | -- scan for nonexistent portals, if they exist remove them from the portals table. If redlinks=yes, then don't remove |
| + | local portallen = #portals |
| + | -- traverse the list backwards to ensure that no portals are missed (table.remove also moves down the portals in the list, so that the next portal isn't checked if going fowards. |
| + | -- going backwards allows us to circumvent this issue |
| + | for i=portallen,1,-1 do |
| + | -- the use of pcall here catches any errors that may occour when attempting to locate pages when the page name is invalid |
| + | -- if pcall returns true, then rerun the function to find if the page exists |
| + | if not pcall(checkPortalExists, portals[i]) or not checkPortalExists(portals[i]) then |
| + | -- Getting here means a redlinked portal has been found |
| + | if (args.redlinks == 'yes') or (args.redlinks == 'y') or (args.redlinks == 'true') or (args.redlinks == 'include') then |
| + | -- if redlinks as been set to yes (or similar), add the cleanup category and then break the loop before the portal is removed from the list |
| + | root:wikitext('[[Category:Portal templates with redlinked portals]]') |
| + | break |
| + | end |
| + | -- remove the portal (this does not happen if redlinks=yes) |
| + | table.remove(portals,i) |
| + | end |
| + | end |
| + | |
| + | -- if the length of the table is different, then rows were removed from the table, so portals were removed. If this is the case add the cleanup category |
| + | if not (portallen == #portals) then |
| + | if #portals == 0 then |
| + | return '[[Category:Portal templates with all redlinked portals]]' |
| + | end |
| + | root:wikitext('[[Category:Portal templates with redlinked portals]]') |
| + | end |
| + | |
| + | -- Start the list. This corresponds to the start of the wikitext table in the old [[Template:Portal]]. |
| + | local listroot = root:tag('ul') |
| + | :css('display', 'table') |
| + | :css('box-sizing', 'border-box') |
| + | :css('padding', '0.1em') |
| + | :css('max-width', '175px') |
| + | :css('width', type(args.boxsize) == 'string' and (args.boxsize .. 'px') or nil) |
| :css('background', '#f9f9f9') | | :css('background', '#f9f9f9') |
| :css('font-size', '85%') | | :css('font-size', '85%') |
| :css('line-height', '110%') | | :css('line-height', '110%') |
− | :css('max-width', '175px') | + | :css('font-style', 'italic') |
− | :css('width', type(args.boxsize) == 'string' and (args.boxsize .. 'px') or nil) | + | :css('font-weight', 'bold') |
− | | |
− | -- If no portals have been specified, display an error and add the page to a tracking category.
| |
− | if not portals[1] then
| |
− | tableroot:wikitext('<strong class="error">No portals specified: please specify at least one portal</strong>[[Category:Portal templates without a parameter]]')
| |
− | end
| |
| | | |
| -- Display the portals specified in the positional arguments. | | -- Display the portals specified in the positional arguments. |
Line 104: |
Line 144: |
| | | |
| -- Generate the html for the image and the portal name. | | -- Generate the html for the image and the portal name. |
− | tableroot | + | listroot |
| :newline() | | :newline() |
− | :tag('tr') | + | :tag('li') |
− | :css('vertical-align', 'middle') | + | :css('display', 'table-row') |
− | :tag('td') | + | :tag('span') |
| + | :css('display', 'table-cell') |
| + | :css('padding', '0.2em') |
| + | :css('vertical-align', 'middle') |
| :css('text-align', 'center') | | :css('text-align', 'center') |
− | :wikitext(string.format('[[File:%s|32x28px|alt=Portal icon|class=noviewer]]', image)) | + | :wikitext(string.format('[[File:%s|32x28px|class=noviewer]]', image)) |
| :done() | | :done() |
− | :tag('td') | + | :tag('span') |
− | :css('padding', '0 0.2em') | + | :css('display', 'table-cell') |
| + | :css('padding', '0.2em 0.2em 0.2em 0.3em') |
| :css('vertical-align', 'middle') | | :css('vertical-align', 'middle') |
− | :css('font-style', 'italic')
| |
− | :css('font-weight', 'bold')
| |
| :wikitext(string.format('[[Portal:%s|%s%sportal]]', portal, portal, args['break'] and '<br />' or ' ')) | | :wikitext(string.format('[[Portal:%s|%s%sportal]]', portal, portal, args['break'] and '<br />' or ' ')) |
| end | | end |
Line 123: |
Line 165: |
| | | |
| function p._image(portals) | | function p._image(portals) |
− |
| |
| -- Wrapper function to allow getImageName() to be accessed through #invoke. | | -- Wrapper function to allow getImageName() to be accessed through #invoke. |
− | return getImageName(portals[1]) | + | local name = getImageName(portals[1]) |
| + | return name:match('^(.-)|') or name -- FIXME: use a more elegant way to separate borders etc. from the image name |
| end | | end |
| | | |