모듈:Adjacent stations
Jump to navigation
Jump to search
이 틀은 루아를 사용합니다: |
본 모듈은 {{Adjacent stations}}, {{Rail icon}}, {{Rail color box}}, {{Line link}}, {{Station link}},{{Rail color}}을 구현합니다. 해당 틀 사용 방법에 대한 설명서는 해당 틀 페이지를 참조하십시오. (이 모듈의 변환 기능에 대한 지시 사항은 {{Adjacent stations}} 문서에 있습니다.)
위에서 언급한 틀은 본 모듈(목록)의 하위 페이지에 저장된 데이터를 사용합니다.
기존 예제를 따라 데이터를 작성하고 편집할 수 있지만 루아에 대한 지식이 있으면 실수를 방지하는데 도움이 됩니다. 이전에 루아를 프로그래밍하거나 사용한 경우 다음 하위 문단을 건너뛸 수 있습니다.
용어[edit source]
- 루아에는 "data types"가 있습니다. 여기서 관련된 것은 "불리언(boolean)", "문자열(string)", "숫자(number)", "테이블(table)"입니다.
- 불리언(boolean)은
true
또는false
입니다. - 문자열(string)은 텍스트로, 문자 목록으로 저장됩니다. 루아에는 코드 내에서 문자열을 표시하는 여러 가지 방법이 있지만, 여기 루아 예에서 문자열은 큰따옴표로 묶어서 표시합니다(예:
"이것은 문자열이다"
). - 숫자(number)는
0.5
또는42
와 같은 숫자값입니다. - 테이블(Table)은 다른 테이블을 포함하여 다른 개체를 포함할 수 있는 구조입니다.
- 빈 테이블은 코드에서
{}
처럼 보입니다. - 테이블에는 키(keys)와 값(values)이 있으며 일반적으로 다음과 같은 구조입니다.
["key"] = value
. 각 키-값은 쉼표로 구분됩니다. 여기에 사용된 모든 키는 문자열 또는 숫자입니다. {"text", "more text"}
는{[1] = "text", [2] = "more text"}
와 같습니다.
- 빈 테이블은 코드에서
- 불리언(boolean)은
- 변수(variable)는
local variable_name = "value"
를 사용하여 정의할 수 있습니다. - 공백(Whitespace)은 탭, 줄바꿈 또는 기타 공간입니다. 루아에서는 공백이 중요하지 않지만, 텍스트가 있는 인라인을 제외한 모든 예는 가독성을 위해 깔끔하게 들여쓰기되어 있으며 별도의 행에 별도의 테이블 키가 있습니다.
- 반환문(return statement)은 (예:
return variable_name
) 함수를 종료하고variable_name
값을 보고합니다. 여기서 function(함수)는 서브 페이지를 호출하는 기본 모듈의 코드이며variable_name
은 데이터 테이블이어야 합니다.
기본 구조[edit source]
- 두 가지 필수 테이블 항목은 "station format(역 형식)"및 "lines(노선)"입니다. 전자는 역 항목에 대한 링크를 형성하기위한 데이터가 있는 테이블이고, 후자는 각 노선에 대한 테이블을 포함하는 테이블입니다.
- 체계명(system title)은 테이블 헤더 행의 중간 셀에 있는 텍스트입니다.
- 역 형식(station format)은 역 항목 및 예외에 대한 기본이름 형식을 정의합니다. 첫 번째 변수 ("%1 역")이 기본값입니다. 예외는 키-값 쌍(예: "강남"–"강남역")으로 나열되며 키는 입력이름입니다. 모듈은 "%1"을 입력으로 대체하여, 입력이름을 표시하고 형식화된 이름으로 항목에 대한 링크를 표시합니다. 또는 전체 위키링크를 입력합니다. 이는 디스플레이가 입력과 다를때 사용할 수 있습니다.
- 노선(lines)은 노선이 나열되는 곳입니다. 여기의 이름은 내부적으로 사용되며 표시되지 않으므로 간결한 이름을 선택하십시오.
- 노선명(line title)은 노선을 나타내는 각 행의 중간에 표시되는 텍스트입니다. "왼쪽 종착역(left terminus)"은 왼쪽 끝의 기본 역명이고 "오른쪽 종착역(right terminus)"은 오른쪽 끝의 기본 역명입니다.
- 각 "색상(color)"항목은 노선의 색입니다.
계층 구조 및 인수 목록[edit source]
- 테이블의 첫번째 계층은 전체 시스템의 데이터와 출력 옵션입니다.
- 시스템 테이블 아래에 노선 목록이 있습니다.
- 세번째 계층은 주어진 노선에 대한 데이터입니다.
- 각 줄에는 '유형(types)'을 가질 수 있습니다. 운행계통 유형 또는 노선의 지선일 수 있습니다.
- 다섯번째 계층은 주어진 유형에 대한 데이터입니다.
지정하지 않으면 모든 키와 값이 문자열입니다.
첫번째 계층 (1)[edit source]
변수 | 유형 | {{Adjacent stations}}에 사용 | 상제 |
---|---|---|---|
["lang"]
|
String | 틀:Yes | 값은 "en-US" 및 "en-GB" 입니다. 설정하지 않으면 "en-GB" 로 간주됩니다.
|
["system title"]
|
String | 틀:Yes | 헤더의 가운데 셀에 있는 텍스트. |
["system icon"]
|
String | 틀:Yes | {{Adjacent station}} 헤더의 중간 셀과 {{Rail icon}}에서 사용된 이미지. |
["system icon format"]
|
String | 틀:No | {{Rail icon}}에서 사용되는 아이콘 유형. "image" 가 아닌 값을 지정하면 {{Rail color box}}를 구현하는 함수에 값이 전달됩니다.
|
["system color"]
|
String | 틀:No | RGB 16진수 코드( "BE2D2C" 또는 "039" 와 같은 3~6자). {{Rail color}}에서 하나의 매개변수만 사용하여 호출할 수 있습니다.
|
["header stop noun"]
|
String | 틀:Yes | 좌우 머리글 셀에서 'preceding(앞에)'및 'following(뒤에)'이후에 나오는 명사. 기본값은 "station" 입니다.
|
["name format"]
|
String | 틀:No | {{철도역 정보}}의 헤더 및 틀:Para와 함께 style 함수를 사용하는 기타 CSS. 값은 문자열 또는 중첩테이블일 수 있으며 첫 번째 층은 행에 해당합니다 ({{철도역 정보}}의 틀:Para에 있는 값). 두 번째 층은 현재 사용되지 않습니다. 키가 없는(즉, 1 키가 있는) 중첩 테이블의 첫 번째 항목이 기본값입니다.
|
["header background color"]
|
String | 틀:No | {{철도역 정보}} 서브 헤더 및 틀:Para와 함께 style 기능을 사용하는 다른 것들을 위한 RGB 16진수 코드. 기본값은 밝은 회색입니다. 값은 "name format" 과 같은 문자열 또는 중첩테이블일 수 있습니다.
|
["header text color"]
|
String | 틀:No | {{철도역 정보}} 서브 헤더 및 틀:Para와 함께 style 기능을 사용하는 다른 것들을 위한 RGB 16진수 코드. 기본값은 헤더 배경색을 기준으로 출력됩니다. 값은 "name format" 과 같은 문자열 또는 중첩테이블일 수 있습니다.
|
["station format"]
|
Table or string | 틀:Yes | 역 형식 문자열을 포함하는 테이블. 지정된 키가 없는 첫 번째 항목(예 : 키가 숫자 1 )이 기본값이며, 다른 모든 항목에는 입력에 해당하는 키가 있어야합니다. 위키링크 괄호가 없는 형식 문자열은 입력(일반적으로 역명)이 표시된 텍스트로 사용되는 링크로 변환됩니다. 이 틀에 전달된 노선 및 노선 유형을 기반으로 옵션을 나타내기 위해 이 테이블 내에 테이블을 중첩시킬 수 있습니다.
|
["lines"]
|
Table | 틀:Yes | 노선 테이블을 포함하는 데이터 테이블. |
["aliases"]
|
Table | 틀:Yes | 노선의 별칭(테이블 키)을 포함하는 테이블(값). 입력은 소문자로 사용하여 대소문자를 구분하지 않으므로, 모든 키는 소문자입니다. |
역 형식 테이블 (2)[edit source]
변수 | 유형 | {{Adjacent stations}}에 사용 | 상제 |
---|---|---|---|
[1]
|
String | 틀:Yes | 기본 형식. |
["non-default station name"]
|
String or table | 틀:Yes | 기본 형식이 아닌 역 또는 특정 노선의 테이블 형식. |
노선별 형식 테이블 (3)[edit source]
변수 | 유형 | {{Adjacent stations}}에 사용 | 상제 |
---|---|---|---|
[1]
|
String | 틀:Yes | 기본 형식. |
["line name"]
|
String or table | 틀:Yes | 기본 형식이 아닌 역 또는 특정 유형의 테이블 형식. |
유형별 형식 테이블 (4)[edit source]
변수 | 유형 | {{Adjacent stations}}에 사용 | 상제 |
---|---|---|---|
[1]
|
String | 틀:Yes | 기본 형식. |
["type name"]
|
String | 틀:Yes | 기본 형식이 아닌 역. |
노선 테이블 (3)[edit source]
["_default"]
라는 가상 노선을 추가하여 모든 노선의 기본값을 설정할 수 있습니다. 현재 두 가지 매개 변수에 사용할 수 있습니다.
변수 | 유형 | {{Adjacent stations}}에 사용 | 상제 |
---|---|---|---|
["title"]
|
String | 틀:Yes | 중간 셀에 표시되는 텍스트, 일반적으로 라인 기사에 대한 링크. 지정하지 않으면 ["_default"] 의 데이터가 사용된다 (기본값의 %1 은 별칭 교체 후 입력으로 대체됨).
|
["short name"]
|
String | 틀:No | {{Rail color box}}에서 사용하는 노선명 |
["icon"]
|
String | 틀:No | {{Rail icon}}에서 사용하는 이미지. |
["icon format"]
|
String | 틀:No | {{Rail icon}}에서 사용하는 아이콘 유형. "image" 가 지정되지 않은 경우, 이 값은 {{Rail color box}}}를 구현하는 함수에 값이 전달된다.
|
["color"]
|
String | 틀:Yes | RGB hex 값. 노선은 ["_default"] 색상으로 (있는 경우), 또는 색상이 없는 경우 체계 색상으로 돌아갑니다. 유형은 노선색 (있는 경우), ["_default"] 색상(있는 경우) 또는 체계 색상으로 돌아갑니다. 이 색상은 {{Adjacent stations}}의 두 번째 및 네 번째 열에 사용되며 강조된 색상으로 {{Rail color box}} 및 {{Rail icon}}에 의해 사용됩니다. 기본적으로 유형과 해당 노선의 색상이 모두 같으면 노선 색상은 중간 셀의 노선명에 대한 배경색(다음 부분 참조)으로 처리됩니다. 유형의 배경색을 "" 또는 "transparent" 로 설정하여 끌 수 있습니다.
|
["background color"]
|
String | 틀:Yes | RGB hex 값(3글자 또는 6글자). 이 색상은 선택 사항이며 중간 셀의 노선명 뒤에만 표시됩니다. 이 모듈은 배경 위에 표시되는 모든 텍스트를 읽을 수 있도록 투명성이 추가되었습니다. |
["border color"]
|
String | 틀:No | {{Rail color box}}에서 사용하는 RGB hex 코드. |
["text color"]
|
String | 틀:No | {{Rail color box}}에서 사용하는 RGB hex 코드. |
["left terminus"]
|
String | 틀:Yes | 일반적으로 노선의 왼쪽 종착역이다. 기본적으로 역이 여러 개 있는 경우 값은 번호가 매겨진 값을 포함하는 테이블이어야 한다.(예: ["left terminus"] = {"Chesham", "Amersham"} ). 해당 테이블의 ["via"] 키를 사용하여 'via' 및 값의 역 링크를 추가할 수 있습니다.
|
["right terminus"]
|
String | 틀:Yes | 일반적으로 노선의 오른쪽 종착역은 ["left terminus"] 와 동일하게 동작한다.
|
["note-mid"]
|
String | 틀:Yes | 행 및 유형 이름 아래의 기본 작은 텍스트. transclusion에서 틀:Para로 대체되었습니다. |
["circular"]
|
Boolean | 틀:Yes | 값이 true 인 경우 종착역은 '방면'/'행' 없이 표시됩니다.
|
["oneway-left"]
|
Boolean | 틀:Yes | 값이 true 이면 왼쪽에 종착역 대신 '일방운행'이 표시됩니다.
|
["oneway-right"]
|
Boolean | 틀:Yes | oneway-left의 오른쪽 대응 인수. |
["types"]
|
Table | 틀:Yes | 노선 유형 테이블을 포함하는 테이블. |
유형 테이블 (5)[edit source]
변수 | 유형 | {{Adjacent stations}}에 사용 | 상제 |
---|---|---|---|
["title"]
|
String | 틀:Yes | 노선 유형의 이름입니다. {{Adjacent stations}}에서는 중간 셀의 노선명 아래에 보통 크기의 텍스트로 표시됩니다. {{Rail color box}}에서는 일부 옵션의 경우 노선명 뒤에 표시되며, 간격을 공백으로 구분되어 표시됩니다. (이는 무정차역 문자에도 사용됩니다.) 유형 이름을 표시하지 않으려면 공백으로 구분되어 표시됩니다 (이는 논스톱 텍스트에도 사용됨). 유형 이름을 표시하지 않으려면 "" 로 설정합니다.
|
["short name"]
|
String | 틀:No | {{Rail color box}}에서 사용하는 노선명. |
["icon"]
|
String | 틀:No | {{Rail icon}}에서 사용하는 이미지. |
["icon format"]
|
String | 틀:No | {{Rail icon}}에서 사용하는 아이콘 유형. "image" 가 아닌 값을 지정하면 {{Rail color box}}를 구현하는 함수에 값이 전달됩니다.
|
["color"]
|
String | 틀:Yes | RGB 색상값. lines은 ["_default"] 색상(있는 경우) 또는 자체 색상이 없는 경우 시스템 색상으로 돌아갑니다. types는 노선의 색(있는 경우), ["_default"] 색상(있는 경우) 또는 시스템의 색으로 돌아갑니다.
기본적으로 유형과 해당 줄의 색상이 모두 같으면 중간 셀의 줄 이름에 대한 배경색(다음 섹션 참조)으로 처리됩니다. 유형의 배경색을 |
["background color"]
|
String | 틀:Yes | RGB 색상값(3자 또는 6자) 이 색상은 선택 사항이며 중간 셀의 노선 이름 뒤에만 표시됩니다. 모듈은 배경 위에 표시되는 모든 텍스트를 읽을 수 있도록 투명성을 추가합니다. |
["border color"]
|
String | 틀:No | {{Rail color box}}에서 사용되는 RGB 색상값. |
["text color"]
|
String | 틀:No | {{Rail color box}}에서 사용되는 RGB 색상값. |
["left terminus"]
|
String | 틀:Yes | 일반적으로 노선의 왼쪽 종착역. 노선 종단부를 재정의합니다. 기본적으로 여러역이 있는 경우 값은 숫자값이 포함된 테이블이어야 합니다. (예: ["left terminus"] = {"Chesham", "Amersham"} ). 해당 테이블의 ["via"] 키를 사용하여 'via'및 값의 역 링크를 추가할 수 있습니다.
|
["right terminus"]
|
String | 틀:Yes | 일반적으로 노선의 오른쪽 종착역. ["left terminus"] 와 동일하게 동작합니다.
|
["note-mid"]
|
String | 틀:Yes | 행 및 유형 이름 아래의 기본 작은 텍스트. transclusion에서 틀:Para로 대체되었습니다. |
require('Module:No globals')
local p = {}
local lang = 'en-GB' -- local default language
-- Below these comments: Internationalization table
-- How to translate this module (for languages without variants):
-- • Characters inside single and double quotation marks are called strings.
-- The strings in this i18n table are used as output.
-- • Strings within square brackets are keys.
-- • Strings are concatenated (joined) with two dots.
-- • Set the string after «local lang =» to your language's code.
-- Change the first key after "i18n" (usually "en-GB") to the same thing.
-- • For each string which is not inside a function, translate it directly.
-- • Strings with keys named "format" are Lua regular expressions.
-- «()» is a match; «.+» means all characters; «%s+» means all spaces.
-- • For each string which is concatenated to the variable «var»,
-- translate the phrase assuming that «var» will be a noun.
-- • Remove any unnecessary translations.
local i18n = require("Module:Adjacent stations/i18n")
local function getData(system, verify)
if verify then
local title = mw.title.new('Module:Adjacent stations/' .. system -- .. '/sandbox'
)
if not (title and title.exists) then return nil end
end
return require('Module:Adjacent stations/' .. system -- .. '/sandbox'
)
end
local function getLine(data, lineN)
if lineN then
if data['aliases'] then
lineN = data['aliases'][mw.ustring.lower(lineN)] or lineN
end
local default = data['lines']['_default'] or {}
local line = data['lines'][lineN] or {}
for k, v in pairs(default) do
if v then line[k] = line[k] or v end
end
line['title'] = line['title'] and mw.ustring.gsub(line['title'], '%%1', lineN)
return line, lineN
end
end
local function getColor(data, system, line, Type, frame)
if system then
if line then return frame:expandTemplate{ title = system .. ' color', args = {line, ['branch'] = Type} } end
return frame:expandTemplate{ title = system .. ' color' }
else
line = (getLine(data, line))
local default = data['lines']['_default']
if line or default then
default = default or {}
if not line then line = mw.clone(default) end
local color = line['color'] or line['background color'] or default['color'] or default['background color'] or data['system color']
local Type_value = Type and line['types'] and (line['types'][Type] and line['types'][Type]['color'])
if Type_value then color = Type_value end
return color
end
return (default and (default['color'] or default['background color']) or data['system color'] or '')
end
end
local lineN, typeN
local function getStation(station, _Format)
if type(_Format) == 'table' then
_Format = _Format[lineN] or _Format[1]
if type(_Format) == 'table' then
_Format = _Format[typeN] or _Format[1]
end
end
if typeN then _Format = mw.ustring.gsub(_Format, '%%3', typeN) end
if lineN then _Format = mw.ustring.gsub(_Format, '%%2', lineN) end
return (mw.ustring.match(_Format, '%[%[.+%]%]')) and (mw.ustring.gsub(_Format, '%%1', station)) or table.concat({'[[', mw.ustring.gsub(_Format, '%%1', station), '|', station, ']]'})
end
function p._main(_args) -- Arguments are processed here instead of the main function
local yesno = require('Module:Yesno')
local trimq = require('Module:Trim quotes')._trim
local boolean = {
['oneway-left'] = true,
['oneway-right'] = true,
['reverse'] = true,
['reverse-left'] = true,
['reverse-right'] = true
}
local args = {} -- Processed arguments
local index = {} -- A list of addresses corresponding to number suffixes in the arguments
for k, v in pairs(_args) do -- Maps each raw argument to processed arguments by string matching
_args[k] = v:match('^%s*(.-)%s*$')
if _args[k] and _args[k] ~= '' then
local a = mw.ustring.match(k, '^(.*%D)%d+$') or k -- The parameter; address 1 can be omitted
local b = tonumber(mw.ustring.match(k, '^.*%D(%d+)$')) or 1 -- The address for a given argument; address 1 can be omitted
if boolean[a] then
v = yesno(v)
end
if not args[b] then
args[b] = {[a] = v}
table.insert(index, b)
elseif args[b][a] then
return error(i18n[lang]['error_duplicate'](a .. b))
else
args[b][a] = v
end
end
end
table.sort(index)
local function small(s, italic)
return italic and '<div class="isA">' .. s .. '</div>'
or '<div class="smA">' .. s .. '</div>'
end
local style = { -- Style for each cell type
['header cell'] = 'class="hcA"|',
['header midcell'] = 'colspan="3" class="hmA"|',
['body cell'] = 'class="bcA"|',
['body banner'] = 'class="bbA" style="background-color:#',
}
local Format
local function subst(var1, var2)
-- var1 is the terminus or table of termini; var2 is the key for the table of termini
return type(var1) == 'string' and getStation(var1, (Format[var1] or Format[1]))
or type(var1) == 'table' and #var1 > 0 and getStation(var1[var2], (Format[var1[var2]] or Format[1]))
or ''
end
local function station(var)
if Format then
if type(var) == 'string' then
return subst(var)
elseif type(var) == 'table' and #var > 0 then
local t = {subst(var, 1)}
for i = 2, #var - 1 do
t[i] = i18n[lang]['comma'](subst(var, i))
end
if #var > 1 then t[#var] = i18n[lang]['or'](subst(var, #var)) end
if var['via'] then
if i18n[lang]['via-first'] then
table.insert(t, 1, i18n[lang]['via'](subst(var, 'via')))
else
table.insert(t, i18n[lang]['via'](subst(var, 'via')))
end
end
return table.concat(t)
else
return ''
end
else
return var or ''
end
end
local function rgb(var)
if var:len() == 3 then
return {tonumber(var:sub(1, 1), 16) * 17, tonumber(var:sub(2, 2), 16) * 17, tonumber(var:sub(2, 2), 16) * 17}
elseif var:len() == 6 then
return {tonumber(var:sub(1, 2), 16), tonumber(var:sub(3, 4), 16), tonumber(var:sub(5, 6), 16)}
end
return {}
end
local data = {} -- A table of data modules for each address
local wikitable = {'{| class="wikitable adjacent-stations"'}
for i, v in ipairs(index) do
-- If an address has a system argument, indexes the data module
data[v] = args[v]['system'] and getData(args[v]['system'])
-- If an address has no system, the row uses data from the previous address
or data[index[i - 1]]
or error(i18n[lang]['error_unknown'](args[v]['system']))
local lang = data[v]['lang'] or lang
if args[v]['system'] then -- Header row
local stop_noun = data[v]['header stop noun'] or i18n[lang]['stop_noun']
table.insert(wikitable, table.concat({'\n|-',
'\n!', style['header cell'], i18n[lang]['preceding'](stop_noun),
'\n!', style['header midcell'], (data[v]['system icon'] and data[v]['system icon'] .. ' ' or ''), (data[v]['system title'] or ('[['.. args[v]['system'] ..']]')),
'\n!', style['header cell'], i18n[lang]['following'](stop_noun)
}))
table.insert(wikitable, '')
table.insert(wikitable, '')
table.insert(wikitable, '')
end
if args[v]['header'] then -- Subheader
table.insert(wikitable, '\n|-\n!colspan="5" class="hmA"|'.. args[v]['header'])
table.insert(wikitable, '')
table.insert(wikitable, '')
table.insert(wikitable, '')
end
if args[v]['line'] or args[v]['left'] or args[v]['right'] or args[v]['nonstop'] then
if not args[v]['line'] and i > 1 and not args[v]['system'] then
args[v]['line'] = args[index[i - 1]]['line']
end
lineN = args[v]['line'] or '_default'
typeN = args[v]['type']
if data[v]['aliases'] then
lineN = data[v]['aliases'][mw.ustring.lower(lineN)] or lineN
if typeN then typeN = data[v]['aliases'][mw.ustring.lower(typeN)] or typeN end
end
-- get the line table
local line = data[v]['lines'] and (mw.clone(data[v]['lines'][lineN]) or error(i18n[lang]['error_unknown'](args[v]['line']))) or error(i18n[lang]['error_line'])
local default = data[v]['lines']['_default'] or {}
line['title'] = line['title'] or default['title']
line['title'] = mw.ustring.gsub(line['title'], '%%1', lineN)
-- cell across row for non-stop service
if args[v]['nonstop'] then
table.insert(wikitable,
table.concat({'\n|-\n|colspan="5" ',
style['body cell'],
((args[v]['nonstop'] == 'former') and i18n[lang]['nonstop_past'] or i18n[lang]['nonstop_present'])(p._box({data = data[v], line = lineN, Type = typeN, inline = 'yes'}))
})
)
table.insert(wikitable, '')
table.insert(wikitable, '')
table.insert(wikitable, '')
else
Format = data[v]['station format'] or i18n[lang]['error_format']
local color, background_color
local Type = line['types'] and line['types'][typeN] -- get the line type table
if Type then
if Type['color'] then
-- line color is used as background if there is no background color in the line type table
background_color = Type['background color'] or line['color']
color = Type['color']
elseif Type['background color'] then
background_color = Type['background color']
color = line['color'] or default['color'] or ''
else
background_color = line['background color']
color = line['color'] or default['color'] or ''
end
else
background_color = line['background color']
color = line['color'] or default['color'] or ''
end
-- Alternate termini can be specified based on type
local sideCell = {true, true}
for i, b in ipairs({'left', 'right'}) do
if not args[v][b] then -- If no station is given on one side, the station is assumed to be the terminus on that side
local _through = args[v]['through-' .. b] or args[v]['through']
local _through_data = getLine(data[v], _through)
if _through_data then _through = _through_data['title'] or _through end
sideCell[i] = _through and "''" .. i18n[lang]['through'](trimq(_through)) .. "''"
or "''" .. trimq((args[v]['reverse-' .. b]
or args[v]['reverse']) and i18n[lang]['reverse']
or i18n[lang]['terminus']) .. "''"
else
local terminusT
local terminusN = Type and Type[b .. ' terminus'] or line[b .. ' terminus']
-- If the terminus table has more than one numbered key or has the via key then the table shows only the default termini, since terminusN[2] cannot be used and terminusN[via] is reserved
if type(terminusN) == 'string' or (type(terminusN) == 'table' and (terminusN[2] or terminusN['via'])) then
if args[v]['to-' .. b] then
terminusT = args[v]['to-' .. b]
local _or = mw.ustring.match(terminusT, i18n[lang]['or-format'])
if _or then
terminusT = mw.ustring.gsub(terminusT, i18n[lang]['or-format'], '\127_OR_\127')
terminusT = mw.ustring.gsub(terminusT, i18n[lang]['comma-format'], '\127_OR_\127')
end
local _via = (mw.ustring.match(terminusT, i18n[lang]['via-format']))
if _via then
terminusT = mw.ustring.gsub(terminusT, i18n[lang]['via-format'], '')
terminusT = mw.text.split(terminusT, '\127_OR_\127')
terminusT['via'] = _via
elseif _or then
terminusT = mw.text.split(terminusT, '\127_OR_\127')
end
else
terminusT = terminusN
end
elseif type(terminusN) == 'table' then
terminusT = terminusN[args[v]['to-' .. b]] or terminusN[args[v]['to']] or terminusN[1]
end
local mainText = args[v]['note-' .. b] and station(args[v][b]) .. small(args[v]['note-' .. b]) or station(args[v][b])
local subText = (args[v]['oneway-' .. b] or line['oneway-' .. b]) and i18n[lang]['oneway']
or args[v][b] == terminusT and i18n[lang]['terminus']
or line['circular'] and terminusT
or i18n[lang]['towards'](station(terminusT))
subText = small(subText, true)
sideCell[i] = mainText .. subText
end
end
table.insert(wikitable, '\n|-')
table.insert(wikitable, '\n|' .. style['body cell'] .. sideCell[1])
table.insert(wikitable, table.concat({'\n|', style['body banner'], color, '"|',
'\n|', (background_color and 'class="bcA" style="background-color:rgba(' .. table.concat(rgb(background_color), ',') .. ',.2)"|' or style['body cell']), line['title'],
-- Type; table key 'types' in subpages (datatype table, with strings as keys). If table does not exist then the input is displayed as the text
(typeN and '<div>' .. (Type and Type['title'] or typeN) .. '</div>' or ''),
-- Note-mid; table key 'note-mid' in subpages. Overridden by user input
((args[v]['note-mid'] and small(args[v]['note-mid'])) or (Type and Type['note-mid'] and small(Type['note-mid'])) or (line['note-mid'] and small(line['note-mid'])) or ''),
-- Transfer; uses system's station link table
(args[v]['transfer'] and small('transfer at ' .. station(args[v]['transfer']), true) or ''),
'\n|', style['body banner'], color, '"|'}))
table.insert(wikitable, '\n|' .. style['body cell'] .. sideCell[2])
end
end
if args[v]['note-row'] then -- Note
table.insert(wikitable, '\n|-\n|colspan="5" ' .. style['body cell'] .. args[v]['note-row'])
table.insert(wikitable, '')
table.insert(wikitable, '')
table.insert(wikitable, '')
end
end
local function combine(t, n)
if t[n + 4] ~= '' and t[n + 4] == t[n] then
t[n + 4] = '' -- The cell in the next row is deleted
local rowspan = 2
while t[n + rowspan * 4] == t[n] do
t[n + rowspan * 4] = ''
rowspan = rowspan + 1
end
t[n] = mw.ustring.gsub(t[n], '\n|class="', '\n|rowspan="' .. rowspan .. '" class="')
end
end
local M = #wikitable
for i = 3, M, 4 do combine(wikitable, i) end
for i = 4, M, 4 do combine(wikitable, i) end
for i = 5, M, 4 do combine(wikitable, i) end
table.insert(wikitable, '\n|}')
return table.concat(wikitable)
end
local getArgs = require('Module:Arguments').getArgs
local function makeInvokeFunction(funcName)
-- makes a function that can be returned from #invoke, using
-- [[Module:Arguments]]
return function (frame)
local args = getArgs(frame, {parentOnly = true})
return p[funcName](args, frame)
end
end
p.main = makeInvokeFunction('_main')
function p._color(args, frame)
local data = args.data
if args[1] or data then
data = data or getData(args[1], true)
if not data then return getColor(nil, args[1], args[2], args[3], frame) end
return getColor(data, nil, args[2], args[3])
end
end
p.color = makeInvokeFunction('_color')
function p._box(args, frame)
local system = args[1] or args.system
lineN = args[2] or args.line
if not (system or lineN) then return '' end
local line, Type, line_data
local inline = args[3] or args.inline
typeN = args.type
local data = args.data
if system or data then
data = data or getData(system, true)
local color
if data then
local default = data['lines']['_default'] or {}
line, lineN = getLine(data, lineN)
if typeN then
typeN = data['aliases'] and data['aliases'][mw.ustring.lower(typeN)] or typeN
Type = line['types'] and line['types'][typeN] and line['types'][typeN]['title'] or typeN
end
color = getColor(data, nil, lineN, typeN)
if inline ~= 'box' then
line_data = line or error(i18n[lang]['error_unknown'](lineN))
line = line_data['title'] or default['title'] or error(i18n[lang]['error_missing']('title'))
line = mw.ustring.gsub(line, '%%1', lineN)
end
else
color = getColor(nil, system, lineN, typeN, frame)
if inline ~= 'box' then
line = frame:expandTemplate{ title = system .. ' lines', args = {lineN, ['branch'] = typeN} }
if mw.text.trim(line) == '' then return error(i18n[lang]['error_unknown'](lineN)) end
end
Type = typeN
end
local result
if Type and Type ~= '' and inline ~= 'box' then
if line == '' then
line = Type
else
result = ' – ' .. Type
end
end
if args.note then result = (result or '') .. ' ' .. args.note end
result = result or ''
if not inline then -- [[Template:Legend]]
result = '<div class="legend" style="-webkit-column-break-inside:avoid;page-break-inside:avoid;break-inside:avoid-column"><span class="legend-color" style="display:inline-block;width:1.5em;height:1.5em;margin:1px 0;border:1px solid black;background-color:#' .. color .. '"> </span> ' .. line .. result .. '</div>'
elseif inline == 'yes' then
result = '<span style="background-color:#' .. color .. ';border:1px solid #000"> </span> ' .. line .. result
elseif inline == 'box' then
result = '<span style="background-color:#' .. color .. ';border:1px solid #000"> </span>' .. result
elseif inline == 'link' then
local link = args.link or mw.ustring.match(line, '%[%[([^%[:|%]]+)[|%]]')
if link then
result = '[[' .. link .. '|<span style="background-color:#' .. color .. ';border:1px solid #000"> </span>]]' .. result
else
result = '<span style="background-color:#' .. color .. ';border:1px solid #000"> </span>' .. result
end
elseif inline == 'square' then
result = '<span style="color:#' .. color .. ';line-height:initial">■</span> ' .. line .. result
elseif inline == 'lsquare' then
local link = args.link or mw.ustring.match(line, '%[%[([^%[:|%]]+)[|%]]')
if link then
result = '[[' .. link .. '|<span style="color:#' .. color .. ';line-height:initial">■</span>]]'
else
result = '<span style="color:#' .. color .. ';line-height:initial">■</span>'
end
elseif inline == 'dot' then
result = '<span style="color:#' .. color .. ';line-height:initial">●</span> ' .. line .. result
elseif inline == 'ldot' then
local link = args.link or mw.ustring.match(line, '%[%[([^%[:|%]]+)[|%]]')
if link then
result = '[[' .. link .. '|<span style="color:#' .. color .. ';line-height:initial">●</span>]]'
else
result = '<span style="color:#' .. color .. ';line-height:initial">●</span>'
end
elseif inline == 'small' then
result = '<span style="background-color:#' .. color .. '"> </span>' .. ' ' .. line .. result
else
local yesno = require("Module:Yesno")
local link = args.link or mw.ustring.match(line, '%[%[([^%[:|%]]+)[|%]]')
local border_color, text_color
if line_data then
if line_data['types'] and line_data['types'][typeN] then
local Type_data = line_data['types'][typeN]
border_color = Type_data['border color'] or line_data['border color'] or color
text_color = Type_data['text color'] or line_data['text color']
lineN = Type_data['short name'] or line_data['short name'] or lineN
else
border_color = line_data['border color'] or color
text_color = line_data['text color']
lineN = line_data['short name'] or lineN
end
else
border_color = color
end
local greatercontrast = require('Module:Color contrast')._greatercontrast
text_color = text_color and '#' .. text_color or greatercontrast{color}
local bold = (yesno(args.bold) == false) or ';font-weight:bold'
if inline == 'route' then -- [[Template:RouteBox]]
if link then
result = '<span style="background-color:#' .. color .. ';border:.075em solid #' .. border_color .. ';padding:0 .3em">[[' .. link .. '|<span style="color:' .. text_color .. bold .. ';font-size:inherit;white-space:nowrap">' .. lineN .. '</span>]]</span>'
else
result = '<span style="background-color:#' .. color .. ';border:.075em solid #' .. border_color .. ';padding:0 .3em;color:' .. text_color .. bold .. ';font-size:inherit;white-space:nowrap">' .. lineN .. '</span>'
end
elseif inline == 'croute' then -- [[Template:Bahnlinie]]
if link then
result = '<span style="background-color:#' .. color .. ';border:.075em solid #' .. border_color .. ';border-radius:.5em;padding:0 .3em">[[' .. link .. '|<span style="color:' .. text_color .. bold .. ';font-size:inherit;white-space:nowrap">' .. lineN .. '</span>]]</span>'
else
result = '<span style="background-color:#' .. color .. ';border:.075em solid #' .. border_color .. ';border-radius:.5em;padding:0 .3em;color:' .. text_color .. bold .. ';font-size:inherit;white-space:nowrap">' .. lineN .. '</span>'
end
elseif inline == 'xroute' then -- [[Template:Bahnlinie]]
if link then
result = '<span style="border:.075em solid #' .. border_color .. ';border-radius:.5em;padding:0 .3em">[[' .. link .. '|<span style="color:#' .. color .. bold .. ';font-size:inherit;white-space:nowrap">' .. lineN .. '</span>]]</span>'
else
result = '<span style="border:.075em solid #' .. border_color .. ';border-radius:.5em;padding:0 .3em;color:#' .. color .. bold .. ';font-size:inherit;white-space:nowrap">' .. lineN .. '</span>'
end
else -- [[Template:Legend]] (fallback; duplication to simplify logic)
result = '<div class="legend" style="-webkit-column-break-inside:avoid;page-break-inside:avoid;break-inside:avoid-column"><span class="legend-color" style="display:inline-block;width:1.5em;height:1.5em;margin:1px 0;border:1px solid black;background-color:#' .. color .. '"> </span> ' .. line .. result .. '</div>'
end
end
result = mw.ustring.gsub(result, ':%s*#transparent', ':transparent')
return result
end
end
p.box = makeInvokeFunction('_box')
function p._icon(args, frame)
local system = args[1] or args.system
local line = args[2] or args.line
local Type = args[3] or args.type
local data = args.data
if system or data then
data = data or getData(system)
local icon, Format
line = (getLine(data, line))
if line then
if Type then
Type = data['aliases'] and data['aliases'][mw.ustring.lower(Type)] or Type
Type = line['types'] and line['types'][Type] -- If there's no type table or entry for this type, then it can't have its own icon
Format = Type['icon format'] or data['type icon format']
icon = Type['icon']
end
if not (Format or icon) then
Format = line['icon format'] or data['line icon format']
icon = line['icon']
end
end
if not (Format or icon) then
Format = data['system icon format']
icon = data['system icon']
end
if Format then
if Format ~= 'image' then return p._box({data = data, [2] = (args[2] or args.line), [3] = Format, type = (args[3] or args.type), bold = args.bold, link = args.link}, frame) end
end
local size = args.size
if size then
if mw.ustring.match(size, '%d$') then
size = '|' .. size .. 'px'
else
size = '|' .. size
end
-- Upright values are to be disabled until there is use of upright scaling in subpages; doesn't seem to work anyway as of 2018-08-10
local tmp = {
'|%s*%d*x?%d+px%s*([%]|])', -- '|%s*upright=%d+%.?%d*%s*([%]|])', '|%s*upright%s*([%]|])'
}
if mw.ustring.match(icon, tmp[1]) then
icon = mw.ustring.gsub(icon, tmp[1], size .. '%1')
-- elseif mw.ustring.match(icon, tmp[2]) then
-- icon = gsub(icon, tmp[2], size .. '%1')
-- elseif mw.ustring.match(icon, tmp[3]) then
-- icon = gsub(icon, tmp[3], size .. '%1')
else
icon = mw.ustring.gsub(icon, '(%[%[[^%]|]+)([%]|])', '%1' .. size .. '%2')
end
end
local link = args.link
if link then
if mw.ustring.match(icon, '|%s*link=[^%]|]*[%]|]') then
icon = mw.ustring.gsub(icon, '|%s*link=[^%]|]*([%]|])', '|link=' .. link .. '%1')
else
icon = mw.ustring.gsub(icon, '(%[%[[^%]|]+)([%]|])', '%1|link=' .. link .. '%2')
end
end
local alt = args.alt or link
if alt then
if mw.ustring.match(icon, '|%s*alt=[^%]|]*[%]|]') then
icon = mw.ustring.gsub(icon, '|%s*alt=[^%]|]*([%]|])', '|alt=' .. alt .. '%1')
else
icon = mw.ustring.gsub(icon, '(%[%[[^%]|]+)([%]|])', '%1|alt=' .. alt .. '%2')
end
end
return icon
end
end
p.icon = makeInvokeFunction('_icon')
function p._line(args, frame)
local system = args[1] or args.system
local line = args[2] or args.line
if not line then return '' end
local Type = args[3] or args.type
local data = args.data
if system or data then
data = data or getData(system, true)
if data then
line = (getLine(data, line)) or error(i18n[lang]['error_unknown'](line))
if Type then
Type = data['aliases'] and data['aliases'][mw.ustring.lower(Type)] or Type
Type = line['types'] and line['types'][Type] and line['types'][Type]['title'] or Type
end
line = line['title'] or error(i18n[lang]['error_missing']('title'))
else
line = frame:expandTemplate{ title = system .. ' lines', args = {line, ['branch'] = Type} }
if mw.text.trim(line) == '' then return error(i18n[lang]['error_unknown'](lineN)) end
end
if Type then
if line == '' then
line = Type
else
line = line .. ' – ' .. Type
end
end
return line
end
end
p.line = makeInvokeFunction('_line')
function p._station(args, frame)
local system = args[1] or args.system
local station = args[2] or args.station
if not station then return '' end
lineN = args[3] or args.line
typeN = args[4] or args.type
local data = args.data
if system or data then
data = data or getData(system, true)
if data then
local _Format = data['station format'][station] or data['station format'][1]
if _Format then
if data['aliases'] then
if lineN then
lineN = data['aliases'][mw.ustring.lower(lineN)] or lineN
end
if typeN then
typeN = data['aliases'][mw.ustring.lower(typeN)] or typeN
end
end
station = getStation(station, _Format)
else
station = station or ''
end
else
station = frame:expandTemplate{ title = system .. ' stations', args = {['station'] = station, ['line'] = lineN, ['branch'] = typeN} }
end
return station
end
end
p.station = makeInvokeFunction('_station')
function p._style(args, frame)
local style = args[1] or args.style
local system = args[2] or args.system
local line = args[3] or args.line
local station = args[4] or args.station
local result = {}
local data = args.data
local default = 'background-color:#efefef' -- Default background color for {{Infobox station}}
if system or data then
data = data or getData(system, true)
end
if data then
local function getValue(var)
if type(var) == 'table' then
var = var[line] or var[1]
if type(var) == 'table' then
var = var[station] or var[1]
end
end
if var ~= '' then return var end
end
if style == 'header' then
local tmp = data['name format'] and getValue(data['name format'])
if tmp then table.insert(result, tmp) end
elseif style == 'subheader' then
local tmp = data['header background color'] and getValue(data['header background color'])
if tmp then
table.insert(result, 'background-color:#' .. tmp)
local color = data['header text color'] and getValue(data['header text color'])
if color then
table.insert(result, 'color:#' .. color)
else
local greatercontrast = require('Module:Color contrast')._greatercontrast
if greatercontrast{tmp} == '#FFFFFF' then table.insert(result, 'color:#FFFFFF') end
end
else
table.insert(result, default)
local color = data['header text color'] and getValue(data['header text color'])
if color then table.insert(result, 'color:#' .. color) end
end
end
result = table.concat(result, ';')
elseif system then
local title = 'Template:' .. system .. ' style'
local titleObj = mw.title.new(title)
if titleObj and titleObj.exists then
local tmp
if style == 'header' then
tmp = frame:expandTemplate{ title = title, args = {'name_format', line, station} }
if tmp ~= '' then table.insert(result, tmp) end
elseif style == 'subheader' then
tmp = frame:expandTemplate{ title = title, args = {'thbgcolor', line, station} }
if tmp ~= '' then
table.insert(result, 'background-color:#' .. tmp)
local color = frame:expandTemplate{ title = title, args = {'thcolor', line, station} }
if color ~= '' then
table.insert(result, 'color:#' .. color)
else
local ratio = require('Module:Color contrast')._ratio
if ratio{tmp, '222222'} < 4.5 then table.insert(result, 'color:#FFFFFF') end -- 222222 is the default text color in Vector
end
else
table.insert(result, default)
tmp = frame:expandTemplate{ title = title, args = {'thcolor', line, station} }
if tmp ~= '' then
table.insert(result, 'color:#' .. tmp)
end
end
end
result = table.concat(result, ';')
else
if style == 'subheader' then
result = default
else
result = ''
end
end
else
if style == 'subheader' then
result = default
else
result = ''
end
end
return result
end
function p.style(frame)
local args = getArgs(frame, {frameOnly = true})
return p._style(args, frame)
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 == 0 and square == 0) then
local count = mw.clone(m)+1
while not (curly == 0 and 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