Home
Random
Recent changes
Special pages
Community portal
Preferences
About Stockhub
Disclaimers
Search
User menu
Talk
Contributions
Create account
Log in
Editing
Module:Sandbox/Ythlev/Adjacent stations
Warning:
You are not logged in. Your IP address will be publicly visible if you make any edits. If you
log in
or
create an account
, your edits will be attributed to your username, along with other benefits.
Anti-spam check. Do
not
fill this in!
local p, data, defaultData, lineData, typeData, funcIsAdjacent = {} local function dig(...) -- Digs through a table with sub-tables using arguments as keys, returning the value of the last key argument -- Analogous to returning a file given a file path with sub-folders -- Returns nil if any given sub-table does not exist local arg, n = {...}, select('#', ...) local a, i = arg[1], 1 while a and i < n do a = a[arg[i + 1]] i = i + 1 end return a end local function makeInvokeFunc(funcName) return function (frame) local args = require('Module:Arguments').getArgs(frame) if funcName == '_adjacent' then funcIsAdjacent = true local tableTools = require('Module:TableTools') args = tableTools.numData(args) if args.other then args[1] = args[1] or {} for k, _ in pairs(args.other) do args[1][k] = args[1][k] or args['other'][k] end end return p[funcName](tableTools.compressSparseArray(args)) else args.system = args.system or args[1] if args.system then local s = 'Module:Rail/' .. args.system local t = 'Module:Adjacent stations/' .. args.system data = mw.title.new(s).exists and mw.loadData(s) or mw.title.new(t).exists and mw.loadData(t) end if funcName ~= '_infoboxStation' then args.line = args.line or args[funcName == '_station' and 3 or 2] args['type'] = args['type'] or args[funcName == '_station' and 4 or 3] if funcName ~= '_station' then defaultData = dig(data, 'lines', '_default') if args.line then lineData = dig(data, 'lines', args.line) or dig(data, 'lines', dig(data, 'aliases', string.lower(args.line))) end typeData = dig(lineData, 'types', args['type']) if funcName == '_icon' or funcName == '_box' then args.style = args.style or args.inline or dig(typeData, 'icon format') or dig(lineData, 'icon format') or dig(data, 'system icon format') args.style = args.style == 'image' and nil or args.style funcName = args.style and '_box' end end end return p[funcName](args, not data and frame) end end end p.style = makeInvokeFunc('_infoboxStation') p.infoboxStation = makeInvokeFunc('_infoboxStation') function p._infoboxStation(args, frame) local root = mw.html.create('div') if args[3] == '_subheader' then root:css('background-color', '#EFEFEF') end if args.system then if args[3] == '_subheader' then root:css('color', 'white') end if data then root:css( dig(data, 'infobox station', args[2], args[3]) or dig(data, 'infobox station', args[3]) ) else if args[3] == '_header' then root:cssText(frame:expandTemplate{ title = args.system .. ' style', args = {'name_format'} }) else local thcolor = frame:expandTemplate{ title = args.system .. ' style', args = {'thcolor'} } root:css('color', thcolor and '#' .. thcolor) local thbgcolor = frame:expandTemplate{ title = args.system .. ' style', args = {'thbgcolor'} } root:css('background-color', thbgcolor and '#' .. thbgcolor) end end end return string.match(tostring(root), '<div style="(.*)"></div>') end local function stationTitle(station, line, typ, n) if station and data then local data, link = funcIsAdjacent and data[n] or data if type(data['station format']) == 'table' then local defaultFormat = data['station format'] if type(defaultFormat[station]) == 'table' then local stationFormat = defaultFormat[station] if line then line = stationFormat[line] and line or dig(data, 'aliases', string.lower(line)) end if type(stationFormat[line]) == 'table' then local lineFormat = stationFormat[line] link = lineFormat[typ] or lineFormat[1] else link = stationFormat[line] or stationFormat[1] end else link = defaultFormat[station] or defaultFormat[1] end else link = data['station format'] end link = (string.gsub(link, '%%1', station)) link = line and (string.gsub(link, '%%2', line)) or link link = typ and (string.gsub(link, '%%3', typ)) or link return string.match(link, '%[%[.*%]%]') and link or table.concat({'[[', link, '|', station, ']]'}) end end p.station = makeInvokeFunc('_station') function p._station(args, frame) args.station = args.station or args[2] if data then return stationTitle(args.station, args.line, args['type']) else return frame:expandTemplate{ title = args.system .. ' stations', args = { ['station'] = args.station, ['line'] = args.line, ['branch'] = args['type'] } } end end p.line = makeInvokeFunc('_line') function p._line(args, frame) if data then return typeData and typeData['title'] and table.concat({lineData['title'], ' (', typeData['title'], ')'}) or lineData and lineData['title'] or defaultData and (string.gsub(defaultData['title'], '%%1', args.line or '_default')) else return frame:expandTemplate{ title = args.system .. ' lines', args = {args.line, ['branch'] = args['type']} } end end p.color = makeInvokeFunc('_color') function p._color(args, frame) if data then return mw.text.nowiki( typeData and typeData['color'] or lineData and lineData['color'] or defaultData and defaultData['color'] ) else return frame:expandTemplate{ title = args.system .. ' color', args = {args.line, ['branch'] = args['type']} } end end p.icon = makeInvokeFunc('_icon') function p._icon(args, frame) if data then local s = typedata and typeData['icon'] or lineData and lineData['icon'] or data and data['system icon'] return args.link and (string.gsub(s, '%[%[(.*)|.*%]%]', args.link)) or s else return frame:expandTemplate{ title = 'Rail-interchange', args = {string.lower(args.system), string.lower(args.line), ['size'] = args.size} } end end p.box = makeInvokeFunc('_box') function p._box(args, frame) local root, style = mw.html.create('div'), args.style local colour, lineTitle = p._color(args, frame), p._line(args, frame) if colour then colour = string.match(colour, '#') and colour or '#' .. colour end if args.line then args.line = dig(data, 'lines', args.line) and args.line or dig(data, 'aliases', string.lower(args.line)) end local box = mw.html.create('span') if style == nil then root :addClass('legend') :css('-webkit-column-break-inside', 'avoid') :css('page-break-inside', 'avoid') :css('break-inside', 'avoid-column') box :addClass('legend-color') :css('display', 'inline-block') :css('width', '1.5em') :css('height', '1.5em') :css('margin', '1px') end if style == 'dot' or style == 'ldot' or style == 'square' or style == 'lsquare' then box:css('line-height', 'initial') end if style == 'dot' or style == 'ldot' or style == 'square' or style == 'lsquare' or style == 'xroute' then box:css('color', colour) else box:css('background-color', colour) end if style == nil or style == 'link' or style == 'inline' or style == 'yes' or style == 'box' then box:css('border', '1px solid black') elseif style and string.match(style, 'route') then box :css('border', '.075em solid ' .. ( typeData and typeData['border color'] or lineData and lineData['border color'] or colour ) ) :css('padding', '0 .3em') if style ~= 'route' then box:css('border-radius', '.5em') end end if style and string.match(style, 'route') then box :css('color', typeData and typeData['text color'] or lineData and lineData['text color'] or style == 'xroute' and colour or 'white' ) :css('font-weight', args.bold == 'no' or 'bold') :css('font-size', 'inherit') :css('white-space', 'nowrap') end local boxText = { ['inline'] = string.rep(' ',4), ['yes'] = string.rep(' ',4), ['small'] = string.rep(' ',1), ['link'] = string.rep(' ',4), ['box'] = string.rep(' ', 4), ['dot'] = 'β', ['ldot'] = 'β', ['square'] = 'β ', ['lsquare'] = 'β ', ['route'] = args.line, ['croute'] = args.line, ['xroute'] = args.line } box:wikitext(boxText[style] or string.rep(' ',1)) if style == 'link' or style == 'ldot' or style == 'lsquare' or style and string.match(style, 'route') then if string.match(lineTitle, '|') then root:wikitext((string.gsub(lineTitle, '%[%[.*|(.*)%]%]', tostring(box)))) else root:wikitext((string.gsub(lineTitle, '%]%]', '|' .. tostring(box) .. ']]'))) end elseif style == 'box' then root:wikitext(tostring(box)) else root:wikitext(tostring(box), ' ', lineTitle) end return root end p.main = makeInvokeFunc('_adjacent') p.adjacent = makeInvokeFunc('_adjacent') function p._adjacent(args) local yesNo = require('Module:Yesno') local i18n = require('Module:Adjacent stations/i18n') local root, lang = mw.html.create('table'), 'en-GB' root:addClass('wikitable adjacent-stations') local function renderHeader(stopNoun, systemIcon, systemTitle) root :tag('tr') :tag('th') :addClass('hcA') :wikitext(i18n[lang]['preceding'](stopNoun)) :done() :tag('th') :attr('colspan', 3) :css('vertical-align', 'middle') :wikitext(systemIcon and systemIcon .. ' ' .. systemTitle or systemTitle) :done() :tag('th') :addClass('hcA') :wikitext(i18n[lang]['following'](stopNoun)) end local function renderSubHeader(subHeader) root :tag('tr') :tag('th') :attr('colspan', 5) :addClass('hmA') :wikitext(subHeader) end local function renderSideCell(row, rowSpan, adjacent, terminus, oneWay, circular, through, Reverse, note) local mainText, subText = mw.html.create('div') if adjacent then mainText:wikitext(adjacent) subText = mw.html.create('div') subText:addClass('isA') if adjacent == terminus then subText:wikitext('Terminus') else subText:wikitext(oneWay and 'one-way operation' or circular and terminus or i18n[lang]['towards'](terminus)) end else mainText:css('font-style', 'italic') mainText:wikitext(Reverse and 'Reverses direction' or through and i18n[lang]['through'](through) or 'Terminus') end row :tag('td') :attr('rowspan', rowSpan) :addClass('bcA') :node(mainText) :tag('div') :css('font-size', 'smaller') :wikitext(note) :done() :node(subText) end local function renderMidCells(row, rowSpan, colour, backgroundColour, lineTitle, typeTitle, note, transfer) if colour then colour = string.match(colour, '#') and colour or '#' .. colour end row :tag('td') :attr('rowspan', rowSpan) :addClass('bbA') :css('background-color', colour) :done() :tag('td') :attr('rowspan', rowSpan) :addClass('bcA') :css('background-color', backgroundColour) :wikitext(lineTitle) :tag('div') :wikitext(typeTitle) :done() :tag('div') :css('font-size', 'smaller') :wikitext(note) :done() :tag('div') :addClass('isA') :wikitext(i18n[lang]['transfer'](transfer)) :done() :done() :tag('td') :attr('rowspan', rowSpan) :addClass('bbA') :css('background-color', colour) end local function renderNonStopRow(title, colour, isFormer) if colour then colour = string.match(colour, '#') and colour or '#' .. colour end root :tag('tr') :tag('td') :attr('colspan', 5) :addClass('bcA') :tag('div') :tag('span') :css('border', '1px solid black') :css('background-color', colour) :wikitext(string.rep(' ', 4)) :done() :wikitext(' ', isFormer == true and i18n[lang]['nonstop_past'](title) or i18n[lang]['nonstop_present'](title)) end local function renderNoteRow(note) root :tag('tr') :tag('td') :attr('colspan', 5) :addClass('bcA') :wikitext(note) end local function makeTerminusFunc(n, fallback) return function (side) local termini = fallback(side .. ' terminus') if type(termini) == 'string' then return stationTitle(termini, args[n]['line'], args[n]['type'], n) elseif type(termini) == 'table' then local i, t, to = 1, {}, args[n]['to-' .. side] or args[n]['to'] while termini[i] and to ~= termini[i] do t[i] = stationTitle(termini[i], args[n]['line'], args[n]['type'], n) i = i + 1 end return stationTitle(termini[i], args[n]['line'], args[n]['type'], n) or mw.text.listToText(t, nil, ' or ') end end end data = {} local j, k, l = 2, 2, 2 for i, v in ipairs(args) do args[i]['system'] = args[i]['system'] or args[i - 1]['system'] data[i] = mw.loadData('Module:Adjacent stations/' .. args[i]['system']) lang = data[i]['lang'] or 'en-GB' defaultData = function (n) return dig(data[n], 'lines', '_default') end if args[i]['line'] then args[i]['line'] = dig(data[i], 'lines', args[i]['line']) and args[i]['line'] or dig(data[i], 'aliases', string.lower(args[i]['line'])) or error(i18n[lang]['error_unknown'](args[i]['line'])) else args[i]['line'] = i == 1 and '_default' or args[i - 1]['line'] end lineData = function (n, line) return dig(data[n], 'lines', line or v.line) or dig(data[n], 'lines', dig(data[n], 'aliases', string.lower(line or v.line))) end typeData = function (n) return dig(lineData(n), 'types', v['type']) end local function fallback(parameter, n) return dig(typeData(n or i), parameter) or dig(lineData(n or i), parameter) or dig(defaultData(n or i), parameter) end local terminus = makeTerminusFunc(i, fallback) if i == 1 or args[i]['system'] ~= args[i - 1]['system'] then renderHeader( data[i]['header stop noun'] or i18n[lang]['stop_noun'], data[i]['system icon'], data[i]['system title'] or '[[' .. args[i]['system'] .. ']]' ) end if v.header then renderSubHeader(v.header) end if v.nonstop then renderNonStopRow(fallback('title'), fallback('color'), v.nonstop == 'former') else local row = root:tag('tr') if i > j - 2 then while args[j] and args[j]['left'] == args[i]['left'] and args[j]['to-left'] == args[i]['to-left'] and args[j]['oneway-left'] == args[i]['oneway-left'] and args[j]['note-left'] == args[i]['note-left'] and (args[j]['through-left'] or args[j]['through']) == (args[i]['through-left'] or args[i]['through']) and (args[j]['reverse-left'] or args[j]['reverse']) == (args[i]['reverse-left'] or args[i]['reverse']) and fallback('oneway-left', j) == fallback('oneway-left') and fallback('circular', j) == fallback('circular') and not args[j]['nonstop'] and not args[j]['note-row'] do j = j + 1 end renderSideCell( row, j - i, stationTitle(v.left, v.line, v['type'], i), yesNo(fallback('circular')) and fallback('left terminus') or terminus('left'), yesNo(v['oneway-left'] or fallback('oneway-left')), yesNo(fallback('circular')), (v['through-left'] or v['through']) and dig(lineData(i, v['through-left'] or v['through']), 'title'), yesNo(v['reverse-left'] or v['reverse']), v['note-left'] ) j = j + 1 end if i > k - 2 then while args[k] and args[k]['line'] == args[i]['line'] and args[k]['type'] == args[i]['type'] and args[k]['note-mid'] == args[i]['note-mid'] and not args[k]['nonstop'] and not args[k]['note-row'] do k = k + 1 end renderMidCells( row, k - i, fallback('color'), fallback('background color'), lineData(i)['title'] or (string.gsub(dig(defaultData(i), 'title'), '%%1', v.line)), typeData(i) and typeData(i)['title'], v['note-mid'] or lineData(i)['note-mid'], stationTitle(v.transfer, v.line, v['type'], i) ) k = k + 1 end if i > l - 2 then while args[l] and args[l]['right'] == args[i]['right'] and args[l]['to-right'] == args[i]['to-right'] and args[l]['oneway-right'] == args[i]['oneway-right'] and args[l]['note-right'] == args[i]['note-right'] and (args[l]['through-right'] or args[l]['through']) == (args[i]['through-right'] or args[i]['through']) and (args[l]['reverse-right'] or args[l]['reverse']) == (args[i]['reverse-right'] or args[i]['reverse']) and fallback('oneway-right', l) == fallback('oneway-right') and fallback('circular', l) == fallback('circular') and not args[l]['nonstop'] and not args[l]['note-row'] do l = l + 1 end renderSideCell( row, l - i, stationTitle(v.right, v.line, v['type'], i), yesNo(fallback('circular')) and fallback('right terminus') or terminus('right'), yesNo(v['oneway-right'] or fallback('oneway-right')), yesNo(fallback('circular')), (v['through-right'] or v['through']) and dig(lineData(i, v['through-right'] or v['through']), 'title'), yesNo(v['reverse-right'] or v['reverse']), v['note-right'] ) l = l + 1 end end if v['note-row'] then renderNoteRow(v['note-row']) end end return root end function p.convert(frame) local args = frame.args local code = mw.text.split(mw.ustring.gsub(args[1], '^%s*{{(.*)}}%s*$', '%1'), '%s*}}%s*{{%s*') local system local group = 0 local delete = { ['s-rail'] = true, ['s-rail-next'] = true, ['s-rail-national'] = true, ['s-start'] = true, ['s-rail-start'] = true, ['start'] = true, ['s-end'] = true, ['end'] = true } local order = { 'line', 'left', 'right', 'to-left', 'to-right', 'oneway-left', 'oneway-right', 'through-left', 'through-right', 'reverse', 'reverse-left', 'reverse-right', 'note-left', 'note-mid', 'note-right', 'transfer' -- circular: use module subpage -- state: not implemented } local replace = { ['previous'] = 'left', ['next'] = 'right', ['type'] = 'to-left', ['type2'] = 'to-right', ['branch'] = 'type', ['note'] = 'note-left', ['notemid'] = 'note-mid', ['note2'] = 'note-right', ['oneway1'] = 'oneway-left', ['oneway2'] = 'oneway-right', ['through1'] = 'through-left', ['through2'] = 'through-right' } local remove_rows = {} local data = {} for i, v in ipairs(code) do code[i] = mw.ustring.gsub(code[i], '\n', ' ') local template = mw.ustring.lower(mw.text.trim(mw.ustring.match(code[i], '^[^|]+'))) code[i] = mw.ustring.match(code[i], '(|.+)$') if template == 's-line' then data[i] = {} local this_system = mw.text.trim(mw.ustring.match(code[i], '|%s*system%s*=([^|]+)')) code[i] = mw.text.split(code[i], '%s*|%s*') for m, n in ipairs(code[i]) do local tmp = mw.text.split(n, '%s*=%s*') if tmp[3] then tmp[2] = mw.ustring.gsub(n, '^.-%s*=', '') end tmp[1] = replace[tmp[1]] or tmp[1] if tmp[2] then -- checks for matching brackets local curly = select(2, mw.ustring.gsub(tmp[2], "{", ""))-select(2, mw.ustring.gsub(tmp[2], "}", "")) local square = select(2, mw.ustring.gsub(tmp[2], "%[", ""))-select(2, mw.ustring.gsub(tmp[2], "%]", "")) if not (curly+square==0) then local count = mw.clone(m)+1 while not (curly+square==0) do tmp[2] = tmp[2]..'|'..code[i][count] curly = curly+select(2, mw.ustring.gsub(code[i][count], "{", ""))-select(2, mw.ustring.gsub(code[i][count], "}", "")) square = square+select(2, mw.ustring.gsub(code[i][count], "%[", ""))-select(2, mw.ustring.gsub(code[i][count], "%]", "")) code[i][count] = '' count = count+1 end end data[i][tmp[1]] = tmp[2] end end if (this_system ~= system) or (not system) then system = this_system data[i]['system'] = system else data[i]['system'] = nil end local last = data[i-1] or data[i-2] or data[i-3] if last then for r, s in pairs({ ['hide1'] = {'left', 'to-left', 'note-left', 'oneway-left'}, ['hide2'] = {'right', 'to-right', 'note-right', 'oneway-right'}, ['hidemid'] = {'type', 'note-mid'} }) do if data[i][r] then for m, n in ipairs(s) do if not data[i][n] then data[i][n] = last[n] end end end end end code[i] = {} local X = '|' local Y = (i+group)..'=' if data[i]['system'] then table.insert(code[i], '|system') table.insert(code[i], Y) table.insert(code[i], data[i]['system']) table.insert(code[i], '\n') end for m, n in ipairs(order) do if data[i][n] then table.insert(code[i], X) table.insert(code[i], n) table.insert(code[i], Y) table.insert(code[i], data[i][n]) end end code[i] = table.concat(code[i]) elseif template == 's-note' then code[i] = mw.ustring.gsub(code[i], '|%s*text%s*=', '|header'..i+group..'=') code[i] = mw.ustring.gsub(code[i], '|%s*wide%s*=[^|]*', '') elseif template == 's-text' then code[i] = mw.ustring.gsub(code[i], '|%s*text%s*=', '|note-row'..i+group..'=') elseif delete[template] then code[i] = '' table.insert(remove_rows, 1, i) -- at the start, so that the rows are deleted in reverse order group = group-1 end end for i, v in ipairs(remove_rows) do table.remove(code, v) end code = table.concat(code, '\n') local t = {'{{Adjacent stations', '\n}}'} system = mw.ustring.match(code, '|system(%d*)=') code = mw.ustring.gsub(code, '\n\n+', '\n') if tonumber(system) > 1 then -- If s-line isn't the first template then the system will have to be moved to the top system = mw.ustring.match(code, '|system%d*=([^|]*[^|\n])') code = mw.ustring.gsub(code, '|system%d*=[^|]*', '') code = '\n|system1='..system..code elseif not mw.ustring.match(code, '^[^{%[]*|[^=|]+2=') then -- If there's only one parameter group then there's no need to have line breaks code = mw.ustring.gsub(code, '\n', '') code = mw.ustring.gsub(code, '(|[^=|]+)1=', '%1=') t[2] = '}}' if not mw.ustring.match(code, '[%[{]') then code = mw.ustring.gsub(code, '|[^=|]*=$', '') code = mw.ustring.gsub(code, '|[^=|]*$', '') end end if not mw.ustring.match(code, '[%[{]') then code = mw.ustring.gsub(code, '|[^=|]*=|', '|') code = mw.ustring.gsub(code, '|[^=|]*|', '|') code = mw.ustring.gsub(code, '|[^=|]*=\n', '\n') code = mw.ustring.gsub(code, '|[^=|]*\n', '\n') end return t[1]..code..t[2] end return p
Summary:
Please note that all contributions to Stockhub may be edited, altered, or removed by other contributors. If you do not want your writing to be edited mercilessly, then do not submit it here.
You are also promising us that you wrote this yourself, or copied it from a public domain or similar free resource (see
Stockhub:Copyrights
for details).
Do not submit copyrighted work without permission!
Cancel
Editing help
(opens in new window)
Template used on this page:
Module:Sandbox/Ythlev/Adjacent stations/doc
(
edit
)