Dieses Modul ist Teil der Formatvorlage Radroutenliste

Lies Dir bitte vor der Verwendung die Anleitung dort durch. Insbesondere sollten die Vorlagen nur in Artikeln der Art Liste der Radrouten in .. verwendet werden. Statt Radrouten ist auch Radwanderrouten, Touristische Radrouten, und leider auch Radwanderwege, Radfernwege, Fernradwege, etc. gebräuchlich. Der Begriff Radweg ist mehrdeutig, siehe die BKL Radweg.

Dieses Modul transkludiert vorübergehend die folgenden Vorlagen:

Nachdem diese Vorlagen in Lua-Module übersetzt wurden, können die Transklusionen durch Funktionsaufrufe der dann entstandenen Module ersetzt werden.


local xp = {}

-- TODO: import this from an external module once similar one exists
xp.countrycode = {
 BG="[[Bulgarien|BG]]",
 CZ="[[Tschechien|CZ]]",
 NO="[[Norwegen|NO]]",
 PL="[[Polen|PL]]",
 D ="[[Deutschland|D]]",
 BW="[[Baden-Württemberg|BW]]",
 BY="[[Bayern|BY]]",
 BB="[[Brandenburg|BB]]",
 BE="[[Berlin|BE]]",
 DE="[[Deutschland|DE]]",
 SH="[[Freie Hansestadt Bremen|HB]]",
 HH="[[Hamburg|HH]]",
 HE="[[Hessen|HE]]",
 MV="[[Mecklenburg-Vorpommern|MV]]",
 NI="[[Niedersachsen|NI]]",
 NW="[[Nordrhein-Westfalen|NW]]",
 RP="[[Rheinland-Pfalz|RP]]",
 SL="[[Saarland|SL]]",
 SN="[[Sachsen|SN]]",
 ST="[[Sachsen-Anhalt|ST]]",
 SH="[[Schleswig-Holstein|SH]]",
 TH="[[Thüringen|TH]]",
 coda="''coda''",
}
xp.countrycode[""]=""

function cond(c, t, f)
    if c then return t else return f end
end

-- genRefs solely exists to workaround a bug in Mediawiki:
-- If ANY input parameter contains <ref> these are translated to strip markers.
-- _Regardless_ of wheter any of them are returned, Mediawiki complains about a
-- missing <references> section.
-- Use '&lt;ref ' instead of '<ref ' and decide here wheter ref tags are to be
-- expanded or not.
function genRefs(f, s)
    if mw.title.getCurrentTitle().isTalkPage
       then return s
           :gsub('&lt;ref [^>]*/>', '')
           :gsub('&lt;ref [^>]*>[^>]*</ref>', '')
       else return f:preprocess(s:gsub('&lt;ref ', '<ref '))
    end
end

function genSortkey(s) -- use DIN 5007-1
    return s
    :gsub("^.[^!]+!", ""):gsub("%[%[[^]]-|([^]]-)]]", "%1") -- strip wikilink
    :gsub("ä", "a"):gsub("Ä", "A")
    :gsub("ö", "o"):gsub("Ö", "O")
    :gsub("ü", "u"):gsub("Ü", "U")
    :gsub("ß", "ss")
    :gsub("%f[%w].", function(s) return s:upper() end) -- upper first in word
    :gsub("[^%w_]", '') -- strip any character not a letter nor an underscore
end

function xp.getArgs(frame)
    local ret = {}
    local f = frame

    if frame.getParent and frame:getParent() and
        mw.title.getCurrentTitle().subjectNsText~="Vorlage"
    then f = frame:getParent()
    end

    -- lowercase argument names and preprocess refs
    for k, v in pairs(f.args)
    do ret[k:lower()] = genRefs(f, v)
    end

    -- map alternative argument names
    for k, v in pairs(frame.alt_arg_names)
    do for sk, _ in pairs(v)
        do if ret[sk] then ret[k] = ret[sk] end
        end

        -- assign nil parms a default if given or the empty string
        if not ret[k] then ret[k] = cond(v.default, v.default, "") end
    end

    return ret
end

function xp.wikilink(frame)
    setmetatable(frame.args, {__index={sep=""}})
    local ret = ""
    local s, sep, ext =
        frame.args[1] or frame.args.s,
        frame.args[2] or frame.args.sep,
        nil

    for v in mw.text.gsplit(s, ", *")
    do if #v>0
        then if v:sub(1, 1)=="!"
            then ret = ret..v:sub(2)..sep
            else local t = mw.text.split(v:gsub('!.*$',
                    function(s) return s:gsub(':',"&#58;") end), ": *")

                if #t>1
                then
                    if not ext
                    then ext  = t[1]
                         t[1] = cond(#t[1]>3,"","<small>").."("..
                                xp.countrycode[t[1]]..": "
                    elseif ext==t[1]
                    then t[1] = ""
                    else ext  = t[1]
                         t[1] = xp.countrycode[t[1]]..": "
                    end
                else     t[2] = t[1]
                         t[1] = ""
                    if ext
                    then ret  = ret:sub(1, #ret - #sep)
                         t[1] = ")"..cond(#ext>3,"","</small>")..sep
                         ext  = nil
                    end
                end

                if #t[2]>0
                then
                    ret = ret..t[1].."[["..mw.ustring.gsub(
                      t[2]:gsub('!','|'):gsub("Bad ", "Bad&nbsp;"),
                      "^([^|]-)([^|%w–]?)(%w+–[%w–]*)([^|%w–]?)([^|]-)$",
                      "%0|%1%2<span style=\"white-space:nowrap\">%3</span>%4%5")
                    .."]]"..sep
                else
                    ret = ret..t[1]:gsub(": $", "")..sep
                end
            end
        end
    end

    if #ret>0
    then ret = ret:sub(1, #ret - #sep)..cond(ext, ")</small>", "")
    end

    return ret
end

function xp.row(frame)
    frame.alt_arg_names = {
        logo   = { symbol=1, zeichen=1, icon=1 },
        ldim   = { lsize=1 },
        name   = { titel=1 },
        nalt   = { talt=1, nameerg=1, titelerg=1 },
        nsort  = { tsort=1 },
        _von   = { vonerg=1, starterg=1 },
        von    = { start=1 },
        via    = { ueber=1, stationen=1 },
        bis    = { ende=1, nach=1, ziel=1 },
        _bis   = { biserg=1, endeerg=1, nacherg=1, zielerg=1 },
        km     = { laenge=1 },
        bt     = { bahntrasse=1, bahndamm=1 },
        fc     = { adfc=1, minkrit=1 },
        rk     = { rundkurs=1 },
        region = { iso_rgn=1 },
        pkarte = { karte=1, lagekarte=1, positionskarte=1 },
        profil = { kommentar=1 }
    }

    local a = xp.getArgs(frame)

    math.randomseed(os.time()-os.clock()*1000)
    math.random()
    math.random()

    -- if no sortkey is given, plain name is used
    a.nsort = genSortkey(a.nsort..a.name)

    -- wikilink strings
    for p in mw.text.gsplit("name nalt von bis", " ", true)
    do a[p] = xp.wikilink{ args = { a[p], ", " } }
    end
    for p in mw.text.gsplit("via _von _bis", " ", true)
    do a[p] = xp.wikilink{ args = { a[p], "&nbsp;↔ " } }
    end

    -- column logo/pikto, Spalte Logo/Piktogramm
    if #a.ldim==0 then a.ldim = "48x48px" end
    if #a.logo>0 and not a.logo:find("[[", 1, true)
    then a.logo = "[[Datei:"..a.logo.."|"..a.ldim.."]]"
    end

    -- column name/title, Spalte Name/Titel und Ergänzung falls angegeben
    if #a.nalt>0 then a.nalt = ", <small>"..a.nalt.."</small>" end
    local stname = "data-sort-value=\""..a.nsort.."\"|"

    -- columns start/dst, Spalten von/bis und Prä-/Suffix falls angegeben
    a._von = a._von:gsub("[^>]$", "%0, "):gsub("%)</small>$", "&nbsp;↔%0 ")
    a._bis = a._bis:gsub("^[^<]", ", %0"):gsub("^<small>%(", " %0↔ ")
    local stvon  = "data-sort-value=\""..genSortkey(a.von).."\"|"
    local stbis  = "data-sort-value=\""..genSortkey(a.bis).."\"|"

    -- column length,     Spalte Länge (in Kilometer)
    if #a.km>0 and not a.km:find("km") then a.km = a.km.." km" end

    -- column railtrail,  Spalte Bahntrasse / Bahndamm
    if a.bt:match("[jJyYtT1]")
    then local v = mw.text.split(a.bt, ", *")
        if v[1]:match("weise")
    	then a.bt = "data-sort-value=\"Teilweise"..a.nsort.."\" "..
            frame:expandTemplate{ title = "Teilweise-Feld", args = { "" } }
        else a.bt = "data-sort-value=\"Vollständig"..a.nsort.."\" "..
            frame:expandTemplate{ title = "Ja-Feld", args = { "" } }
        end
        a.bt = a.bt.."[[Datei:BSicon lDAMPF.svg|20px|verweis="..
            cond(v[2], v[2], "").."]]<br/><small>("..v[1]..")</small>"
    else
        if a.bt:match("[-nNfF0]")
        then a.bt = "data-sort-value=\"–Nirgends"..a.nsort.."\" "..
            frame:expandTemplate{ title = "N/A-Feld", args = {} }
        else a.bt = "data-sort-value=\"–Unbekannt"..a.nsort.."\"|"
        end
    end

    -- column wayquality, Spalte Mindestkriterien / Fahrradclub / ADFC
    if a.fc:match("[jJyYtT1-9]")
    then a.fc = frame:expandTemplate{ title = "Ja-Feld", args = { "" } }..
        "<span style='font-size:larger'>"..cond(a.fc:match("[1-9]"), a.fc, "").."&#9733;</span>"
    elseif a.fc:match("[-nNfF0]")
    then a.fc = frame:expandTemplate{ title = "Nein-Feld", args = { "" } }..
        "<span style='font-size:larger'>&#10008;</span>"
    end

    -- column roundtrip,  Spalte Rundkurs
    if a.rk:match("[jJyYtT1]")
    then a.rk = "data-sort-value=\"Einer"..a.nsort.."\" "..
        frame:expandTemplate{ title = "Ja-Feld", args = { "<span style='font-size:larger'>♺</span>" } }
    elseif a.rk:match("[mMvV]")
    then a.rk = "data-sort-value=\"Viele"..a.nsort.."\" "..
        frame:expandTemplate{title = "Ja-Feld", args = { "♺ ♺<br/>♺" } }
    elseif a.rk:match("[-nNfF0]")
    then a.rk = frame:expandTemplate{ title = "N/A-Feld", args = {} }
    end

    -- column minimap,    Spalte Mini-Lagekarte
    if #a.pkarte>0
    then local img, fmt, lnk, ipos, ivert = nil, "|64px", "", "left", "-18px"
        for v in mw.text.gsplit(a.pkarte, ", *")
        do  if v:sub(1, 1)=="!"
            then fmt = v:gsub("!", "|")
            elseif v:find("^%d+$")
            then lnk = "https://cycling.waymarkedtrails.org/#route?type=relation&id="..v
            elseif v:find("^r%d+$")
            then lnk = "http://www.openstreetmap.org/relation/"..v:sub(2)
            elseif v:find("^%[")
            then lnk = v
            else img = "File:"..v
            end
        end

        lnk = lnk:gsub("^http.*", "|verweis=%0|Lagekarte unter %0 aufrufen")
                 :gsub("^%[+(.-)%]+$", "|verweis=%1|%1")

        if a.region == "DE-SN" or a.region == "DE-TH"
        then ipos = "right"
        end

        if a.region == "DE-TH"
        then ivert = "-58px;height:58px"
        end

        a.pkarte = "style=\"background:#E0E0E0;padding:.2em 0em\"|[["..img..fmt..
            lnk.."]]<div style=\"margin-top:"..ivert..";padding:0em .2em;"..
            "text-align:"..ipos.."\">[[File:Desc-i_gray.svg|18px|verweis="..
            "commons:"..img..'|'..img:sub(5).."]]</div>"
    else
        a.pkarte = [[style="background:#E0E0E0;padding:0px"|]]
    end

    -- return entry depending on page title, default is a table row
    if mw.title.getCurrentTitle().text:find("/[Dd]ruck$", -6)
    then return ";"..a.name
        ..cond(a.nsort:find("[Ww]eg%f[%W%u]"),"\nDer ","\nDie "
            ..cond(a.nsort:find("[Rr]oute%f[%W%u]") or
                a.nsort:find("[Tt]our%f[%W%u]"),"","Radroute "))..a.name.." "
        ..({"verläuft","führt","weist","leitet"})[math.random(1,4)]
        .." von "..a.von.." nach "..a.bis.." "
        ..({"und durchquert","über","durch die Orte", "mit Stationen in",
            "und verbindet","mit Halt in","und erschließt den Radelnden",
            "und zeigt RadlerInnen Landschaft und Natur um"})[math.random(1,8)]
        .." "..a.via:gsub("&nbsp;↔",","):gsub(", ([^,]*)$", " und %1")..". "
        ..({"Die Route","Der Weg","Die Tour",
            cond(a.nsort:find("[Ww]eg%f[%W]"),"Er ","Sie ")})[math.random(1,4)]
        .." ist"..cond(not a.rk:find("♺"),""," als Rundkurs "
            ..({"fahrbar","angelegt","verwirklicht"})[math.random(1,3)].." und")
        .." insgesamt"..a.km:gsub("^.-([%d.,]+)%D-$"," %1&nbsp;Kilometer lang")
        ..cond(not a.km:find("%d+%D+%d"),".",a.km:gsub("^%D-([%d.,]+).-$",
        	", wovon %1&nbsp;km auf "..xp.countrycode[a.region:sub(-2)]
        	    :gsub("^%[?%[?([^]|]*).-$","%1").." entfallen."))
    elseif mw.title.getCurrentTitle().isTalkPage
    then return '*'..a.name
    else return "|-\n|align=\"center\"|"..a.logo.." ||"..stname..a.name..a.nalt
        .." ||"..stvon..a._von..a.von.." ||"..a.via.." ||"..stbis..a.bis..a._bis
        .." ||"..a.km.." ||"..a.bt.." ||"..a.fc.." ||"..a.rk
        .." ||"..a.pkarte.." ||"..a.profil
    end
end

function xp.emptyrow(frame)
    frame.alt_arg_names = {
        farbe = { color=1, colour=1, default = "grey" }
    }

    local a = xp.getArgs(frame)

    -- if used on a Talk/Disk page, supress output
    if mw.title.getCurrentTitle().isTalkPage then return '<!-- // -->' end

    -- return table row entry
    return [[|- style="border-top:]]..a.farbe..[[ 2px solid"]]..'\n'..
        string.rep([[ ||data-sort-value="ZZZ" style="padding:0px"|]], 11)
        :gsub("ZZZ",
            (function()
                local n=0
                return function(s) n=n+1 return cond(n==6, "99999", s) end
            end)())
        :sub(3)
end

function xp.header(frame)
    return [==[
{|class="wikitable sortable"
!class="unsortable"|Logo
!Name
!style="vertical-align:top;padding-left:21px;min-width:64px"|<div style="float:right">[[File:BSicon KBHFaq grey.svg|20px|verweis=]][[File:BSicon LSTRq grey.svg|20px|verweis=]]</div><br/>von
!style="vertical-align:top;padding-left:21px;min-width:64px"|[[File:BSicon LSTRq grey.svg|20px|verweis=]][[File:BSicon HSTq grey.svg|20px|verweis=]][[File:BSicon LSTRq grey.svg|20px|verweis=]]<br/><small>Stationen<br/>(Auswahl)</small>
!style="vertical-align:top;padding-left:21px;min-width:64px"|<div style="float:left">[[File:BSicon LSTRq grey.svg|20px|verweis=]][[File:BSicon KBHFeq grey.svg|20px|verweis=]]</div><br/>bis
!style="min-width:48px" data-sort-type="number"|[[File:BSicon ENDEaq grey.svg|20px|verweis=]][[File:BSicon ENDEeq grey.svg|20px|verweis=]]<br/><small>Länge<br/>(ca.)</small>
![[File:BSicon lDAMPF.svg|x20px|verweis=Bahntrassenradweg|verläuft auf ehem. Bahntrasse]]<br/><small>Bahn&shy;trasse</small>
![[File:ADFC-Logo_2009_1.svg|x20px|verweis=|erfüllt ADFC-Mindeststandards für Radfernwege]]<br/><small>Mindest&shy;standards</small>
!<div style="font-size:large;height:20px;margin-top:-3px;margin-bottom:4px">&#9850;</div><small>Rund&shy;kurs</small>
!class="unsortable"|<div style="height:20px">&nbsp;</div><small>Lage&shy;karte</small>
!class="unsortable"|[[File:RideLondon-Surrey Classic Leith Hill Loop.svg|verweis=|x20px|Streckenprofil, Schwierigkeit]]<br/><small>Streckenprofil&nbsp;und<br/>Kommentare</small>]==]
end

function xp.footer(frame)
    return "|}"
end

--function xp.print_invisible_debug_info(frame)
--    local ret = ""
--    for c in frame.args[1]:gmatch(".")
--    do ret = ret..mw.ustring.format("%x %s ", c:byte(), c)
--    end
--    return "<div style=\"display:none\">this: "..frame:getTitle()..
--        " parent: "..frame:getParent():getTitle()..
--        " namespace: "..mw.title.getCurrentTitle().subjectNsText..
--        " fulltitle: "..mw.title.getCurrentTitle().prefixedText..
--        " hexdump_firstarg: "..ret..
--        "</div>"
--end

return xp