Module:Track gauge/autodocument
Template:Lua
Template:Uses TemplateStyles
This module documents the Track gauge/data data page of {{Track gauge}}. Its main product is Template:Track gauge/doc/input options.
Used by {{Track gauge/document gauge}}
Gauges
- {{Track gauge/document gauge}}, using
documentGauge
Can list in complete tableform one, multiple or all gauges listed in the /data page. Gauges defined in both metric and imperial are grouped into one row.
Per gauge size a link to the category:Articles that mentions this gauge ... is added.
#invoke functions
checkData documentGauge catContent catMentions createCatMentions documentGaugeSizeFromTitle catSortFromTitle
Parameters
|1= alias |1<!--???-->= (datafile for checkData) |n=all (list) |docfrom= |docto= |doctitle= |docstate= |docstats= |displaynotfound= |docsortlabel= |docreturnargs=
Parser limits (expensive functions)
Module:Track gauge/autodocument uses expensive function calls (especially the documentGauge
listing). The wiki parser only allows 500 such calls in one page. As of July 2014, this number is almost reached in (~475 in Template:Track gauge/doc/input options). When, after adding new entries to /data or /extra, the number is reached, a "Script error" will show.
Best practice is to prevent this error: adding content category name to the /data, even if they have default name pattern or do not exist: <syntaxhighlight lang="Lua">
["contentcat"] = "5 ft 3 in gauge railways", -- or ["contentcat"] = "",
</syntaxhighlight> This way, these category pages are not checked for existence.
See also
- Category:Articles that mention a specific track gauge
- {{Track gauge}}
- {{Track gauge/talk useful links}} -- talk page support
- module:Track gauge
- module:Track gauge/data
-- This module documents the track gauges -- as defined in [[module:Track gauge/data]]. -- General note: "id" is the size-id (in mm). With this id, definitions can vary (mm, ft/in, name) -- Alias (the normalised input value) is the primary search term local p = {} local getArgs = require('Module:Arguments').getArgs local modMath = require('Module:Math') local modTrackGauge = require('Module:Track gauge') -- sandbox here local dataPageName = 'Module:Track gauge/data' -- sandbox here local gaugeDataAll = nil local tableTools = require('Module:tableTools') -- global counters (to keep between the id-row building calls) local ttlSizeClassCount = {} local ttlAliasCount = 0 local ttlEntries = 0 local ttlUnitCount = {} local ttlAltNameCount = 0 local ttlAltName = {} local ttlLinkCount = 0 local ttlContentCatsCount = 0 local ttlMentioningCatsCount = 0 local ttlMentioningPageCount = 0 local ttlListedRange = {} ----------------------------------------------------------------------------------- -- prepareArgs -- Arguments coming from an #invoke or from a module ----------------------------------------------------------------------------------- local function prepareArgs(frame) local origArgs = getArgs(frame) -- Trim whitespace, make lower-case and remove blank arguments for all arguments -- searchAlias is the cleaned value of [1]. [1] is kept as rawInput for error message local args = {} args['searchAlias'] = '' args['rawInput'] = origArgs[1] or '' for k, v in pairs(origArgs) do if tonumber(k) == nil then -- Named argument if k == 'docsortlabel' then -- not in TG args[k] = v else args[k] = mw.ustring.lower(v) end else -- Unnamed argument, alias to be searched args[k] = modTrackGauge.normaliseAliasInput(v) if k == 1 then args['searchAlias'] = args[1] end end end return args end ----------------------------------------------------------------------------------- -- formatUnitPlaintext -- Pattern '00016.5 mm' for table.sort and catsort. ----------------------------------------------------------------------------------- local function formatUnitPlaintext(tgEntry, unit, fmtZeroPadding, toFracChar) -- Returns plaintext (ASCII) only. No css. if tgEntry == nil then return '' end if (unit or tgEntry.def) == 'imp' then -- imperial local ft = '' local inch = '' local frac = '' if tgEntry.ft then ft = tgEntry.ft .. ' ft' end if tgEntry.num then frac = ' ' .. tgEntry.num .. '/' .. tgEntry.den if toFracChar then -- as used in contentCat pagenames if frac == ' 1/8' then frac = '⅛' elseif frac == ' 1/4' then frac = '¼' elseif frac == ' 3/8' then frac = '⅜' elseif frac == ' 1/2' then frac = '½' elseif frac == ' 3/4' then frac = '¾' elseif frac == ' 7/8' then frac = '⅞' else frac = frac .. ' (error: fraction character missing in module:Track gauge)' end end if tgEntry['in'] then frac = ' ' .. tgEntry['in'] .. frac .. ' in' else frac = ' ' .. frac .. ' in' end else if tgEntry['in'] then inch = ' ' .. tgEntry['in'] .. ' in' end end return mw.text.trim(ft .. inch .. frac) else -- metric (mm) if fmtZeroPadding == nil or tonumber(fmtZeroPadding) <= 0 then return tgEntry.id .. ' mm' else return string.rep('0', fmtZeroPadding - math.floor(math.log10(tonumber(tgEntry.id))) - 1) .. tgEntry.id .. ' mm' end end end ----------------------------------------------------------------------------------- -- document data-sort-value ----------------------------------------------------------------------------------- local function documentdatasortvalue(tgEntry) local s = formatUnitPlaintext(tgEntry, 'met', 5) return tostring(mw.html.create():tag('span'):attr('data-sort-value', s)) end ----------------------------------------------------------------------------------- -- catSortFromTitle -- Currently finds "600 mm" when at end of title, then returns "0600 mm" (for catSort). -- Blank when not found. Used for cat:mentions category page. ----------------------------------------------------------------------------------- function p.catSortFromTitle() local title = mw.title.getCurrentTitle() local catSort = string.match(title.text, '%s(%d+%.?%d*)%smm$') or '' if catSort ~= '' then catSort = string.rep('0', 4 - math.floor(math.log10(tonumber(catSort))) - 1) .. catSort .. ' mm' end if catSort == '' then return '*' else return catSort end end ----------------------------------------------------------------------------------- -- documentGaugeClass ----------------------------------------------------------------------------------- local function documentGaugeClass(tgEntry, countMentionings) local size = tonumber(tgEntry.id or 0) local j if size > 1435 then j = 5 elseif size == 1435 then j = 4 elseif size > 500 then j = 3 elseif size >= 100 then j = 2 elseif size > 0 then j = 1 else j = 6 end ttlSizeClassCount[j][2] = ttlSizeClassCount[j][2] +1 ttlSizeClassCount[j][4] = ttlSizeClassCount[j][4] + (countMentionings or 0) return '<span data-sort-value="' .. j .. '">' .. ttlSizeClassCount[j][1] .. '</span>' --(20190920: linter closing span added) end ----------------------------------------------------------------------------------- -- anchor -- Anchor text *here* is: <span id="1000 mm">; anchor *there* should be: #1000 mm. ----------------------------------------------------------------------------------- local function anchor(tgEntry, unit, herethere) if tgEntry == nil then return '' end unit = unit or tgEntry.def1 local anch = formatUnitPlaintext(tgEntry, unit, 0) if herethere == 'there' then -- Untested, April 2014 anch = '#' .. anch else anch = mw.html.create():tag('span'):attr('id', anch) end return tostring(anch) end ----------------------------------------------------------------------------------- -- noWrap -- Add span tags to prevent a string from wrapping. ----------------------------------------------------------------------------------- local function noWrap(s) return mw.ustring.format('<span class="nowrap">%s</span>', s) end ----------------------------------------------------------------------------------- -- frac -- A slimmed-down version of the {{frac}} template (a single nowrap to be added with the unit) ----------------------------------------------------------------------------------- local function frac(whole, num, den) local templatestyles = mw.getCurrentFrame():extensionTag{ name = 'templatestyles', args = { src = 'Fraction/styles.css' } } return mw.ustring.format( '%s<span class="frac" role="math">%s<span class="num">%s</span>⁄<span class="den">%s</span></span>', templatestyles, whole and (whole .. '<span class="sr-only">+</span>') or '', num, den ) end ----------------------------------------------------------------------------------- -- debugReturnArgs ----------------------------------------------------------------------------------- function p.debugReturnArgs(frame) local args = prepareArgs(frame) local retArgs = {} for k, a in pairs(args) do table.insert(retArgs, k .. '=' .. a) end return 'Args: ' .. table.concat(retArgs, '; ') end ----------------------------------------------------------------------------------- -- checkData -- Public. Performs various checks on the /data subpage. -- not maintained since ca. 2015 ----------------------------------------------------------------------------------- function p.checkData(frame) --To be allowed: entry.link empty; then use entry.name. local dataPage = frame and frame.args and frame.args[1] or dataPageName local data = mw.loadData(dataPage) local exists, dupes, dupeSort, ret = {}, {}, {}, {} -- Check for duplicate aliases. for ti, t in ipairs(data) do for ai, alias in ipairs(t.aliases or {}) do if not exists[alias] then exists[alias] = { ti, ai } else if not dupes[alias] then dupes[alias] = { exists[alias] } end table.insert(dupes[alias], { ti, ai }) end end end for alias in pairs(dupes) do table.insert(dupeSort, alias) end table.sort(dupeSort) for i1, alias in ipairs(dupeSort) do local positions = {} for i2, aliasKeys in ipairs(dupes[alias]) do local position = mw.ustring.format('gauge %d, alias %d (gauge id: <code>%s</code>)', aliasKeys[1], aliasKeys[2], data[aliasKeys[1]].id or '') table.insert(positions, position) end local aliasText = mw.ustring.format('Duplicate aliases "%s" detected at the following positions: %s.', alias, mw.text.listToText(positions, '; ')) table.insert(ret, aliasText) end -- Check for numerators without denominators. for ti, t in ipairs(data) do local num = t.num local den = t.den if num and not den then table.insert(ret, mw.ustring.format('Numerator "%s" with no denominator detected at gauge %d (id: <code>%s</code>).', num, ti, t.id or '')) elseif den and not num then table.insert(ret, mw.ustring.format('Denominator "%s" with no numerator detected at gauge %d (id: <code>%s</code>).', den, ti, t.id or '')) end end -- Check for gauges with no imperial or no metric measurements. for ti, t in ipairs(data) do if not (t.ft or t['in'] or t.num or t.den) then table.insert(ret, mw.ustring.format('No imperial measurements found for gauge %d (id: <code>%s</code>).', ti, t.id or '')) end if not (t.m or t.mm) then table.insert(ret, mw.ustring.format('No metric measurements found for gauge %d (id: <code>%s</code>).', ti, t.id or '')) end end -- Check for non-numeric measurements. local measurements = { 'ft', 'in', 'num', 'den', 'm', 'mm' } for ti, t in ipairs(data) do for mi, measurement in ipairs(measurements) do local measurementVal = t[measurement] if measurementVal and not tonumber(measurementVal) then table.insert(ret, mw.ustring.format('Non-numeric <code>%s</code> measurement ("%s") found for gauge %d (id: <code>%s</code>).', measurement, measurementVal, ti, t.id or '')) end end end -- Check for gauges with no id. for ti, t in ipairs(data) do if not t.id then local aliases = {} for i, alias in ipairs(t.aliases) do table.insert(aliases, mw.ustring.format('<code>%s</code>', alias)) end aliases = mw.ustring.format(' (aliases: %s)', mw.text.listToText(aliases)) table.insert(ret, mw.ustring.format('No id found for track gauge %d%s.', ti, aliases or '')) end end -- Check for gauges with no aliases. for ti, t in ipairs(data) do if type(t.aliases) ~= 'table' then table.insert(ret, mw.ustring.format('No aliases found for gauge %d (id: <code>%s</code>).', ti, t.id or '')) else local isAlias = false for ai, alias in ipairs(t.aliases) do isAlias = true break end if not isAlias then table.insert(ret, mw.ustring.format('No aliases found for gauge %d (id: <code>%s</code>).', ti, t.id or '')) end end end -- Check for named gauges with no links and gauges with links but no names. -- 20140520: no link? could be acceptable. Code falls back to the unlinked name (in test now). if false then -- skipped 2014-05-25 for ti, t in ipairs(data) do if t.name and not t.link then table.insert(ret, mw.ustring.format('No link found for the named gauge "%s" at position %d (id: <code>%s</code>).', t.name, ti, t.id or '')) elseif t.link and not t.name then table.insert(ret, mw.ustring.format('No name found for the gauge with link "%s" at position %d (id: <code>%s</code>).', t.link, ti, t.id or '')) end end end -- Check for invalid def1 values. for ti, t in ipairs(data) do local def = t.def1 if def ~= 'imp' and def ~= 'met' then table.insert(ret, mw.ustring.format('Invalid def1 value "%s" found for gauge %d (id: <code>%s</code>).', def or '', ti, t.id or '')) end end -- Check for unwanted whitespace. for ti, t in ipairs(data) do for tkey, tval in pairs(t) do if tkey == 'aliases' and type(tval) == 'table' then for ai, alias in ipairs(tval) do if mw.ustring.find(alias, '%s') then table.insert(ret, mw.ustring.format('Unwanted whitespace detected in gauge %d alias %d ("%s", gauge id: <code>%s</code>).', ti, ai, alias, t.id or '')) end end elseif tkey == 'name' or tkey == 'link' or tkey == 'pagename' or tkey == 'contentcat' then if tval ~= mw.text.trim(tval) then table.insert(ret, mw.ustring.format('Unwanted whitespace detected in <code>%s</code> field of gauge %d ("%s", gauge id: <code>%s</code>).', tkey, ti, tval, t.id or '')) end elseif mw.ustring.find(tval, '%s') then table.insert(ret, mw.ustring.format('Unwanted whitespace detected in <code>%s</code> field of gauge %d ("%s", gauge id: <code>%s</code>).', tkey, ti, tval, t.id or '')) end end end -- Added April 2014: alias should not double with another id (imp and mm not ambiguous) local self_id = '' local self_def = '' for ti, t in ipairs(data) do self_id = t.id self_def = t.def1 for iC, aliasCheck in ipairs(t.aliases) do if tonumber(aliasCheck) ~= nil then if self_id ~= aliasCheck then for iTwo, tTwo in ipairs(data) do if aliasCheck == tTwo.id then table.insert(ret, mw.ustring.format('Input alias %s (%s) from <code>id=%s mm</code> ambiguous with gauge id=<code>%s mm</code> (%s)' , aliasCheck, self_def, self_id, tTwo.id, tTwo.def1) ) end end end end end end -- Return any errors found. for i, msg in ipairs(ret) do ret[i] = mw.ustring.format('<span class="error">%s</span>', msg) end if #ret > 0 then return mw.ustring.format('Found the following errors in %s:\n* %s', dataPage, table.concat(ret, '\n* ')) else return mw.ustring.format('No errors found in %s.', dataPage) end end ----------------------------------------------------------------------------------- -- catContent -- content category for the gauge ----------------------------------------------------------------------------------- function p.catContent(frame) -- catContent (content category for this alias) -- can be hardcoded in the data, or build by size (pattern) local args = prepareArgs(frame) local tgEntry = modTrackGauge.getTrackGaugeEntry(args.searchAlias) if tgEntry == nil then return args['displaynotfound'] or 'No gauge entry found for ' .. (args[1] or '""') end local catTitle local label local catC local docsortlabel = '' if args.docsortlabel ~= nil then docsortlabel = '|' .. args.docsortlabel end if tgEntry.contentcat == '' then catC = '' elseif tgEntry.contentcat ~= nil then catC = '[[:Category:' .. tgEntry.contentcat .. docsortlabel .. ']]' else -- no name given, try default name: local catCsuffix = ' gauge railways' if tgEntry.def1 == 'met' then label = formatUnitPlaintext(tgEntry, 'met') catTitle = mw.title.makeTitle(14, label .. catCsuffix) if catTitle.exists then catC = '[[:' .. catTitle.fullText .. docsortlabel .. ']]' end elseif tgEntry.def1 == 'imp' then label = formatUnitPlaintext(tgEntry, 'imp', nil, true) catTitle = mw.title.makeTitle(14, label .. catCsuffix) if catTitle.exists then catC = '[[:' .. catTitle.fullText .. docsortlabel .. ']]' end end end return catC end ----------------------------------------------------------------------------------- -- catMentions -- maintenance only ----------------------------------------------------------------------------------- function p.catMentions(frame) local args = prepareArgs(frame) local tgEntry = modTrackGauge.getTrackGaugeEntry(args.searchAlias) if tgEntry == nil then return args['displaynotfound'] or 'No gauge entry found for ' .. (args[1] or '""') end local catM = modTrackGauge.catMentions(tgEntry, args.docsortlabel, 'show') return catM end ----------------------------------------------------------------------------------- -- fromInputToId -- Used cleaned Alias as searchkey ----------------------------------------------------------------------------------- local function fromInputToId(searchAlias) gaugeDataAll = mw.loadData(dataPageName) for i, tgEntry in ipairs(gaugeDataAll) do for j, alias in ipairs(tgEntry.aliases) do if alias == searchAlias then return tgEntry.id end end end -- Next search: by id (autodocument only, not in main RG) if tonumber(searchAlias) ~= nil then for i, tgEntry in ipairs(gaugeDataAll) do if tgEntry.id == searchAlias then return tgEntry.id end end end end ----------------------------------------------------------------------------------- -- documentInchCount -- Number of inches in decimals. ----------------------------------------------------------------------------------- local function documentInchCount(tgEntry) local inches = 0 if tgEntry['num'] ~= nil then inches = modMath._round(tonumber((tgEntry['num'] or 0) / (tgEntry['den'] or 1)), 4) end inches = tostring((tonumber(tgEntry['ft'] or 0) * 12) + tonumber(tgEntry['in'] or 0) + inches) return inches end ----------------------------------------------------------------------------------- -- documentInchToMm -- Not used lately ----------------------------------------------------------------------------------- local function documentInchToMm(inchCount) return tonumber(inchCount or 0) * 25.4 end ----------------------------------------------------------------------------------- -- documentGaugeSizeFromTitle -- Currently finds "1620 mm" when at end of title, -- then returns "1620". Blank when not found. ----------------------------------------------------------------------------------- function p.documentGaugeSizeFromTitle() local title = mw.title.getCurrentTitle() return string.match(title.text, '%s(%d+%.?%d*)%smm$') or '' end ----------------------------------------------------------------------------------- -- documentBuildTgList -- The table of id's to fill the table ----------------------------------------------------------------------------------- function documentBuildTgList(args) -- Build series from the list. idFrom and idTo are numerical local tgList = {} local idFrom = -1 local idTo = -1 for i, v in ipairs(args) do if v == 'all' then idFrom = -math.huge idTo = math.huge break end end if args.docfrom ~= nil then idFrom = tonumber(fromInputToId(args.docfrom) or mw.ustring.gsub(args.docfrom, 'mm', '')) idTo = math.huge end if args.docto ~= nil then idTo = tonumber(fromInputToId(args.docto) or mw.ustring.gsub(args.docto, 'mm', '')) end if idTo > 0 then -- Some subset is requested from the whole data set if idFrom > idTo then local dummy = idFrom idFrom = idTo idTo = dummy end for i, tgEntry in ipairs(gaugeDataAll) do if (tonumber(tgEntry.id) >= idFrom) and (tonumber(tgEntry.id) <= idTo) then table.insert(tgList, tonumber(tgEntry.id)) end end tgList = tableTools.removeDuplicates(tgList) table.sort(tgList) if #tgList > 1 then ttlListedRange[1] = tgList[1] .. ' mm – ' .. tgList[#tgList] .. ' mm ' end end -- Individual entries can be mentioned in args (all unnamed = numbered params) -- Need a straight table.to keep sequence right local id local argsAliasesIn = tableTools.compressSparseArray(args) for i, argsAlias in ipairs(argsAliasesIn) do id = fromInputToId(argsAlias) if id ~= nil then table.insert(tgList, i, tonumber(id)) table.insert(ttlListedRange, i, id .. ' mm; ') end end ttlListedRange = tableTools.compressSparseArray(ttlListedRange) ttlListedRange = tableTools.removeDuplicates(ttlListedRange) tgList = tableTools.compressSparseArray(tgList) tgList = tableTools.removeDuplicates(tgList) return tgList end ----------------------------------------------------------------------------------- -- documentPostListStats -- build footer table, after list only ----------------------------------------------------------------------------------- local function documentPostListStats(countTgList) -- Report data counters -- Data local retFoot = {} table.insert(retFoot, '\n*Sources') table.insert(retFoot, ':Data pages: [[:' .. dataPageName .. ']]') table.insert(retFoot, '*Data') table.insert(retFoot, ':Listed: ' .. table.concat(ttlListedRange, '') .. ' (' .. countTgList .. ' rows)') table.insert(retFoot, ":'''Entries''' (defined gauges, per unit): " .. ttlEntries) table.insert(retFoot, ":'''Gauges''' (defined gauges, per size): " .. countTgList) for i, stat in ipairs (ttlUnitCount) do table.insert(retFoot, ':' .. stat[2] .. ': ' .. stat[1]) end table.insert(retFoot, ':Aliases (input options): ' .. ttlAliasCount) table.insert(retFoot, ':Named definitions (as output link; ' .. ttlAltNameCount .. '): ' .. table.concat(ttlAltName, '; ')) table.insert(retFoot, ':Entries with an article link: ' .. ttlLinkCount) -- TODO table.insert(retFoot, '*Named gauges (named input)') -- todo -- Categories (content, maintenance) table.insert(retFoot, '*Categories') table.insert(retFoot, ':Content categories: ' .. ttlContentCatsCount) table.insert(retFoot, ':"Article mentions track gauge" categories: ' .. ttlMentioningCatsCount) table.insert(retFoot, ':Articles listed in "mentions" categories: ' .. ttlMentioningPageCount .. ' (not unique)') -- Size classes (narrow, broad, ..) table.insert(retFoot, '*Size classes') for i, stat in ipairs (ttlSizeClassCount) do if stat[2] ~= 0 then table.insert(retFoot, ':' .. stat[2] .. ' ' .. stat[3] .. ' (' .. stat[4] .. ' mentionings)') end end local anchor = tostring(mw.html.create():tag('span'):attr('id', 'Statistics')) -- help:using colors. Hue=190 (blue) local statTable = anchor .. '\n{| class="wikitable collapsible collapsed" style="background:#e6fbff; font-size:85%; width:100%;"' .. '\n|-' .. '\n! style="background:#ceecf2; width:100%;" | Track gauge data statistics' .. '\n|-' .. '\n|' .. table.concat(retFoot, '\n') .. '\n|}' return statTable end ----------------------------------------------------------------------------------- -- documentHeader ----------------------------------------------------------------------------------- local function documentHeader(numberOfEntries, docTitle, docState) local docBgHeader = '#cef2e0' -- Green. See [[template:documentation]] -- Header row 1 (title) local pagetitle = mw.title.getCurrentTitle() urlPurgePage = 'https://en.wikipedia.org/w/index.php?title=' .. pagetitle.nsText .. ':' .. pagetitle:partialUrl() .. '&action=purge' urlPurgePage = '<span class="plainlinks purgelink nourlexpansion" title="Purge this page (update countings)">[' .. urlPurgePage .. ' (purge)]</span>' if docTitle == '' then docTitle = 'Track gauges' -- (' .. dataPageName .. ')' -- optional, sandbox here end docTitle = docTitle .. ' ' .. urlPurgePage if docState == '' then docState = 'uncollapsed' end -- Header row 2 (sort buttons, blank cells) local sortColHeaders = '' local sortClass = '' if (numberOfEntries or 0) > 1 then sortClass = 'sortable' local sortCell = '! style="background:' .. docBgHeader .. ';"' -- todo: 10 cols with bg color sortColHeaders = '\n|- style="background:' .. docBgHeader .. '; line-height:90%;"' .. '\n! || || || || || || || || ||' end -- Header row 3 (column headers) local catMparent = modTrackGauge.catMentions(nil, 'Mentionings', 'show') --10 columns: local tableStyle = 'style="text-align:right; width:100%; font-size:85%;" ' local retHdr = {} table.insert(retHdr, '\n{| class="wikitable collapsible ' .. docState .. ' ' .. sortClass .. '" ' .. tableStyle) table.insert(retHdr, '|-') table.insert(retHdr, '! colspan=10 style="background:' .. docBgHeader .. ';" | ' .. docTitle) table.insert(retHdr, '|-') table.insert(retHdr, '! style="background:' .. docBgHeader .. ';" | Gauge<br>(mm)') table.insert(retHdr, '! style="background:' .. docBgHeader .. ';" | Gauge<br>(ft, in)') table.insert(retHdr, '! style="background:' .. docBgHeader .. ';" | Alt<br>name') table.insert(retHdr, '! style="background:' .. docBgHeader .. ';" | Gauge<br>(inch)') table.insert(retHdr, '! style="background:' .. docBgHeader .. ';" | Def<br>unit') table.insert(retHdr, '! style="background:' .. docBgHeader .. '; width:8em;" | Aliases<br>(input options)') table.insert(retHdr, '! style="background:' .. docBgHeader .. ';" | Class<br> ') table.insert(retHdr, '! style="background:' .. docBgHeader .. '; min-width:5em;" | Source<br>article') table.insert(retHdr, '! style="background:' .. docBgHeader .. ';" | [[:Category:Track gauges by size|Category]]<br>(content)') table.insert(retHdr, '! style="background:' .. docBgHeader .. ';" | ' .. catMparent .. '<br>(maintenance)') return table.concat(retHdr, '\n') .. sortColHeaders end ----------------------------------------------------------------------------------- -- documentFooter ----------------------------------------------------------------------------------- local function documentFooter() return {'\n|}'} end ----------------------------------------------------------------------------------- -- documentFromIdToEntrySet -- from fromIdToEntrySet -- From one id, make the set with all one-two-three-more entries (met, inp, variants) ----------------------------------------------------------------------------------- local function documentFromIdToEntrySet(id, searchedAlias) local docBgColor = '#e6fff2' -- Green. See header bg color local rowSplit = '<div style="border-top:1px solid #ccc; height:1px;"></div>' -- From the size-id, build the set of existing entries (met, imp, and variants) local entry = {} local defType = 0 -- data for i, tgEntry in ipairs(gaugeDataAll) do if id == tgEntry.id then if tgEntry.def1 == 'met' and entry[1] == nil then entry[1] = tgEntry defType = defType + 1 elseif tgEntry.def1 == 'imp' and entry[2] == nil then entry[2] = tgEntry defType = defType + 2 else entry[3 + tableTools.size(entry)] = tgEntry end end end entry = tableTools.compressSparseArray(entry) -- Entry set is now complete & clean -- Result: the entry table with entries present in /data, -- in sequence if present (1. met, 2. imp, any extra) -- (to build into a single row, maybe with split cells) --Build cell elements, then string row together. local inchCount = documentInchCount(entry[1]) local datasortvalue = documentdatasortvalue(entry[1], 'met', 5) local aliasList = {} local tempEntryAltName = {} local entryAltName = {} local hasAltName = false for i, e in ipairs(entry) do local alis = {} for j, v in ipairs(e.aliases) do if tonumber(v) == nil then -- (plain numbers are not shown) table.insert(alis, tostring(v)) end end for j, v in ipairs(alis) do if string.match(v, '^%d') == nil then -- textual so to italic. alis[j] = tostring(mw.html.create():tag('span'):wikitext(v):css('font-style', 'italic')) end end table.insert (aliasList, table.concat(alis, '; ')) ttlAliasCount = ttlAliasCount + #alis -- process Alt name links if e.name or '' ~= '' then tempEntryAltName[i] = tostring(mw.html.create():tag('span'):wikitext(e.link):css('font-weight', 'bold')) table.insert(ttlAltName, e.id .. ': ' .. e.link) ttlAltNameCount = ttlAltNameCount + 1 hasAltName = true end end if hasAltName then local text for i, v in ipairs(entry) do table.insert(entryAltName, i, tempEntryAltName[i] or ' ') end end local def = {} -- Definition unit code: 'met' or 'imp' local defText = {} for i, v in ipairs (entry) do table.insert(def, v.def1) if v.def1 == 'imp' then table.insert(defText, 'imp') ttlUnitCount[2][1] = ttlUnitCount[2][1] + 1 elseif v.def1 == 'met' then table.insert(defText, 'met') ttlUnitCount[1][1] = ttlUnitCount[1][1] + 1 end end if #entry >= 2 then if #entry == 2 and entry[1].def1 ~= entry[2].def1 then -- Regular pair: def in met and in imp ttlUnitCount[3][1] = ttlUnitCount[3][1] + 1 else -- More than 2, or a double unit definition ttlUnitCount[4][1] = ttlUnitCount[4][1] .. ' ' .. id .. ' mm (' .. #entry ..');' end end -- mm; ft in -- Measurement (number & unit; met and imp; anchor to here) local measure = {} local unitanchor = { '', '' } measure[1] = modTrackGauge.formatMet(entry[1]) measure[2] = modTrackGauge.formatImp(entry[1]) -- both met and imp from entry[1] if modMath._mod(defType, 2) == 1 then measure[1] = tostring(mw.html.create():tag('span'):wikitext(measure[1]):css('font-weight', 'bold')) unitanchor[1] = anchor(entry[1], 'met') end if defType >= 2 then measure[2] = tostring(mw.html.create():tag('span'):wikitext(measure[2]):css('font-weight', 'bold')) unitanchor[2] = anchor(entry[1], 'imp') end -- Linked article local linkArticle = {} for i, e in ipairs(entry) do table.insert(linkArticle, e.pagename) end ttlLinkCount = ttlLinkCount + #linkArticle local eq if #linkArticle >= 2 then eq = true for i, v in ipairs(linkArticle) do if v ~= linkArticle[1] then eq = false break end end if eq == true then for i, v in ipairs(linkArticle) do if i > 1 then linkArticle[i] = nil end end end end for i, lp in ipairs(linkArticle) do local fmtLp = '' fmtLp = '[[' .. lp .. ']]' linkArticle[i] = tostring(mw.html.create():tag('span'):css('text-align', 'left'):wikitext(fmtLp)) end -- catContent (content category for this alias). note: function p.catContent is a reduced code of this. -- can be hardcoded in the data, or build by size (pattern) local catContent = {} local catTitle local label local skipCheck = false for i, e in ipairs(entry) do if e.contentcat == '' then -- no cat; option to prevent expensive calls skipCheck = true elseif e.contentcat ~= nil then label = string.match(e.contentcat, '([%S]*)') or 'nomatch' table.insert(catContent, '[[:Category:' .. e.contentcat .. '|cat:' .. label .. ' ...]]') end end if #catContent >= 2 then eq = true for i, v in ipairs(catContent) do if v ~= catContent[1] then eq = false break end end if eq == true then for i, v in ipairs(catContent) do if i > 1 then catContent[i] = nil end end end end if #catContent == 0 and not skipCheck then local catCsuffix = ' gauge railways' if modMath._mod(defType, 2) == 1 then label = formatUnitPlaintext(entry[1], 'met') catTitle = mw.title.makeTitle(14, label .. catCsuffix) if catTitle.exists then table.insert(catContent, '[[:' .. catTitle.fullText .. '|cat:' .. noWrap(label) .. ']]') end end if defType >= 2 then label = formatUnitPlaintext(entry[1], 'imp', nil, true) catTitle = mw.title.makeTitle(14, label .. catCsuffix) if catTitle.exists then table.insert(catContent, '[[:' ..catTitle.fullText .. '|cat:' .. noWrap(label) .. ']]') end end end ttlContentCatsCount = ttlContentCatsCount + #catContent -- Mentions category local catMentions = modTrackGauge.catMentions(entry[1], "cat:mnt", 'show') local catCount = mw.site.stats.pagesInCategory( modTrackGauge.catMentions(entry[1], nil, 'pagename'), pages) ttlMentioningCatsCount = ttlMentioningCatsCount + 1 -- Exists ttlMentioningPageCount = ttlMentioningPageCount + catCount -- class: Counter SizeClass (narrow, broad, ...) local rgSizeClass = documentGaugeClass(entry[1], catCount) ttlEntries = ttlEntries + #entry sortCount = mw.text.truncate('00000' .. tostring(catCount), -5, '') sortCount = '<span data-sort-value="' .. sortCount .. '">' catCount = sortCount .. catCount .. ' P' .. '</span>' --(20190920: linter closing span added) -- Compose the size-id row with all cell values (10 columns) local row = {} table.insert(row, datasortvalue .. unitanchor[1] .. measure[1]) table.insert(row, datasortvalue .. unitanchor[2] .. measure[2]) table.insert(row, table.concat(entryAltName, rowSplit)) table.insert(row, datasortvalue .. inchCount) table.insert(row, table.concat(defText, rowSplit)) table.insert(row, table.concat(aliasList, rowSplit)) table.insert(row, rgSizeClass) table.insert(row, table.concat(linkArticle, rowSplit)) table.insert(row, table.concat(catContent, rowSplit)) table.insert(row, catCount .. ' ' .. catMentions) return '\n|- style="background:' .. docBgColor .. '; border-top:2px solid #aaa;" |' .. '\n|' .. table.concat(row, ' || ') end ----------------------------------------------------------------------------------- -- documentGauge -- Selfdocument gauge data (one, multiple, range, all) ----------------------------------------------------------------------------------- function p.documentGauge(frame) local args = prepareArgs(frame) gaugeDataAll = mw.loadData(dataPageName) -- Init glolbal counters by table: ttlUnitCount = { [1] = {0, 'Entries defined metric'}, [2] = {0, 'Entries defined imperial'}, [3] = {0, 'Gauge sizes defined both metric and imperial'}, [4] = {'', 'Gauge sizes with multiple entries in one unit'} } ttlSizeClassCount = { [1] = {'scaled', 0, 'scaled or model gauges', 0}, [2] = {'min', 0, 'minimum gauges', 0}, [3] = {'narrow', 0, 'narrow gauges', 0}, [4] = {'s.g.', 0, 'standard gauge', 0}, [5] = {'broad', 0, 'broad gauges', 0}, [6] = {'unk', 0, 'unknown', 0} } local tgList = documentBuildTgList(args) -- Now loop through the prepared tgList[id] and add rows to result le -- One row contains all available entries for the id (met, imp, a third variant) local rowTGid = {} for i, numId in ipairs(tgList) do table.insert(rowTGid, documentFromIdToEntrySet(tostring(numId))) end -- Return args local retArgs = '' if args.docreturnargs == 'on' then retArgs = '\n' .. p.debugReturnArgs(frame) end -- Build statistics footer local retStats = '' if args.docstats == 'on' then retStats = documentPostListStats(#tgList) end -- Build up return documentHeader(#tgList, args.doctitle or '', args.docstate or '') .. table.concat(rowTGid, '') .. table.concat(documentFooter(), '') .. retStats .. retArgs end -------------------------------------------------------- -- doc -------------------------------------------------------- function p.docFracAliases(frame) local args = prepareArgs(frame) gaugeDataAll = mw.loadData(dataPageName) local tgList = documentBuildTgList(args) local ttlHitCount =0 local rowIMP = {} local fracAlias ='' for i, id in ipairs(tgList) do for j, tgEntry in pairs(gaugeDataAll) do if nil and tostring(id) == '53.975' and tostring(id) == tgEntry.id then fracAlias = anchor(tgEntry, 'imp', 'there') fracAlias = mw.ustring.lower(mw.ustring.gsub(fracAlias, '[%s%,%#]', '')) table.insert(rowIMP, fracAlias .. '||' .. i .. '||' .. id .. '||' .. modTrackGauge.formatImp(tgEntry) .. ' || plus ' .. tgEntry.num) end if tostring(id) == tgEntry.id and tgEntry.def1 == 'imp' and tgEntry.num ~= nil then if tgEntry.ft ~= nil then ttlHitCount = ttlHitCount + 1 fracAlias = anchor(tgEntry, 'imp', 'there') fracAlias = mw.ustring.lower(mw.ustring.gsub(fracAlias, '[%s%,%#]', '')) fracAlias = mw.ustring.gsub(fracAlias, '⁄', '/') table.insert(rowIMP, fracAlias .. '||' .. i .. '||' .. id .. '||' .. modTrackGauge.formatImp(tgEntry)) fracAlias = tostring((tonumber((tgEntry.ft) or 0) * 12) + tonumber(tgEntry["in"] or 0)) .. tgEntry.num .. '/' .. tgEntry.den .. 'in' table.insert(rowIMP, fracAlias .. '||' .. i .. '||' .. id .. '||' .. modTrackGauge.formatImp(tgEntry)) end end end end -- return '\n|' .. ttlHitCount .. ' hits. ' .. #rowIMP return '\n\n|-\n\n|' .. table.concat(rowIMP, '\n\n|-\n\n|') end return p