Module:Jctint/core
Revision as of 02:54, 5 December 2014 by Jackmcbarn (talk) (use mw.html and other fixes from sandbox)
This module implements the {{Jctint/core}} template. Please see the template page for usage instructions.
Usage
{{#invoke:Jctint|jctint}}
Tracking/maintenance categories
- Category:Jctint template using non-numeric parameter values
- Category:Jctint template with invalid type
local p = {} -- Package to be exported local format = string.format -- Local version of string formatting function local types = mw.loadData("Module:Road data/RJL types") -- Import type-based data for colors and tooltips local row -- mw.html object for the generated row local jspan -- Junction span argument is stored here for efficiency local color -- Color specified by any supplied type local title -- Tooltip specified by any supplied type local errorMsg = {} -- Any error messages produced that will be added to the output local function conversion(unit, unitdef) -- This function converts the distance specified in unit from the unit specified in unitdef to the other supported unit local primary = unit and tonumber(unit) or -1 -- If unit is nil, primary will be -1. If unit is a non-numeric string, primary will be nil. Otherwise, primary will be the string as a number. if not primary then -- If primary is nil (unit was non-numeric), add the transcluding page to an error tracking category. local page = mw.title.getCurrentTitle() -- Get transcluding page's title local pagename = page.prefixedText -- Extract page's full title as string local category = format("[[Category:Jctint template using non-numeric parameter values|# %s]]", pagename) -- Create category string table.insert(errorMsg, category) -- Add error category to error message table. return unit -- Return supplied unit elseif primary == -1 then -- If primary is -1 (unit is nil), simply return nil return nil end local mwmath = require "Module:Math" -- Import math module local precision = mwmath._precision -- Function to determine a numeric string's precision local round = mwmath._precision_format -- Function to display a number rounded to a given number of digits local converted -- Distance converted into the secondary unit if unitdef == 'mi' then -- If the primary unit is miles converted = primary * 1.609344 -- Convert into kilometers else -- Otherwise converted = primary / 1.609344 -- Convert into miles end local prec = precision(unit) -- Retrieve precision of supplied distance if prec < 0 then prec = 0 end -- Precision must be at least 0 return round(converted, prec) -- Return the converted distance rounded to the same number of digits as the supplied distance end local function locations(args) -- This function generates the cells for locations. local unitary = args.unitary -- The contents of this parameter will span all of the location columns. if unitary then local tag = row:tag('td'):attr('colspan', 3):wikitext(unitary) -- Simply create a cell that spans all three possible columns, and store the contents of unitary in the cell. local align = args.unitary_align or 'left' -- Determine the alignment of the cell contents, using the unitary_align argument with 'left' as a default. tag:css('text-align', align) -- Apply the text alignment to the cell. else -- We don't have a single cell to create, so now comes the hard work. local areas = {village = "Village", city = "City", town = "Town", community = "Community", CDP = "Community", hamlet = "Hamlet", ["unorganized territory"] = "Unorganized Territory"} -- This is a table of different area types. local notPrimaryTopic = args.primary_topic == 'no' -- If the primary_topic argument equals 'no', then this is true. Otherwise, this is false. -- Regions local regionSpan = args.regionspan -- If this is supplied, a region cell will be created with this as its row span. local region = args.region -- This will be the region stored in a possible region cell, and will also be used for disambiguating other locations. if regionSpan then local regionCell = row:tag('td'):attr('rowspan', regionSpan) -- Create a region cell with the supplied row span. local regionSpecial = args.region_special or ('[[' .. region .. ']]') -- The region_special argument overrides the region argument. If it is not provided, simply wikilink the supplied region. regionCell:wikitext(regionSpecial) -- Store either the contents of the region_special argument or the wikilinked region in the cell. end -- Independent Cities local indepCity = args.indep_city -- Independent cities span both subdivision columns. local indepCitySpecial = args.indep_city_special -- This will override the indep_city argument. local sub1note = args.sub1_note -- This may be used to place a note in small text below the name of an independent city or other first-level subdivision. local sub2span = args.sub2span or 1 -- This is the row span for any independent city or second-level subdivision. 1 is the default. if indepCity or indepCitySpecial then -- If an independent city is provided, create the appropriate cell. local indepCityCell = row:tag('td'):attr('colspan', 2):attr('rowspan', sub2span) -- Create a cell that spans two columns, and has the calculated row span. local align = args.indep_city_align or 'left' -- Determine the alignment of the cell contents, using the indep_city_align argument with 'left' as a default. indepCityCell:css('text-align', align) -- Apply the text alignment to the cell. if indepCitySpecial then -- If indep_city_special is supplied, simply stuff it in the cell. indepCityCell:wikitext(indepCitySpecial) elseif notPrimaryTopic then -- Otherwise, if primary_topic == 'no', then create a wikilink with the independent city and region, and store it in the cell. local text = format('[[Independent city|City]] of [[%s, %s|%s]]', indepCity, region, indepCity) indepCityCell:wikitext(text) else -- If neither is true, then create a wikilink with just the independent city and store it in the cell. local text = format('[[Independent city|City]] of [[%s]]', indepCity) indepCityCell:wikitext(text) end if sub1note then -- If a note is provided, store that in the cell as well. indepCityCell:tag('br', {selfClosing = true}) -- Add a line break to the cell. indepCityCell:tag('small'):wikitext(sub1note) -- Add the note to the cell, within an HTML <small> tag. end else -- If no independent city is provided, create two cells for the first- and second-level subdivisions. -- First-level Subdivisions local sub1 = args.sub1 -- First-level subdivisions include counties and other similar areas. local sub1Special = args.sub1_special -- This will override sub1. local sub1name = args.sub1name -- This is the name of the type of subdivision, like "County" or "Parish" if sub1 or sub1Special then -- If a first-level subdivision is provided, create a table cell for it. local sub1span = args.sub1span or 1 -- This is the row span for the first-level subdivision. 1 is the default. local sub1Cell = row:tag('td'):attr('rowspan', sub1span) -- Create a cell for the location, with the appropriate row span if sub1Special then -- If sub1_special is provided, stuff it in the cell. sub1Cell:wikitext(sub1Special) elseif notPrimaryTopic then -- Otherwise, if primary_topic == 'no', then create a wikilink with the subdivision name, type, and region, and store it in the cell. local text = format('[[%s %s, %s|%s]]', sub1, sub1name, region, sub1) sub1Cell:wikitext(text) else -- If neither is true, create a wikilink with the subdivision name, and optionally the type, and store it in the cell. local text = '[[' .. sub1 if sub1name then -- The type is optional in this case. text = text .. format(' %s|%s', sub1name, sub1) end sub1Cell:wikitext(text .. ']]') end if sub1note then -- If a note is provided, store that in the cell as well. sub1Cell:tag('br', {selfClosing = true}) -- Add a line break to the cell. sub1Cell:tag('small'):wikitext(sub1note) -- Add the note to the cell, within an HTML <small> tag. end end -- Second-level Subdivisions local sub2 = args.sub2 -- Second-level subdivisions include cities and towns local sub2Special = args.sub2_special -- This will override sub2 if (sub2 == 'none') or (sub2 == ' ') then -- If sub2 is 'none' or a non-breaking space, store a non-breaking space in the cell. row:tag('td'):wikitext(" ") -- Create a cell and store a non-breaking space in it. elseif sub2Special then -- If sub2_special is supplied, simply stuff it in the cell. row:tag('td'):attr('rowspan', sub2span):wikitext(sub2Special) -- Create a cell, apply the proper row span, and store the contents of sub2_special. elseif sub2 then -- If sub is supplied, then create and fill the cell. local sub2Cell = row:tag('td'):attr('rowspan', sub2span) -- Create a new cell, and apply the appropriate row span to it. if not notPrimaryTopic then -- If primary_topic ~= 'no', simply wikilink the supplied location and store it in the cell. sub2Cell:wikitext('[[' .. sub2 .. ']]') else -- Otherwise, create a wikilink that includes the region, and store it in the cell. local text = {'[[', sub2} local area = args.area -- This can include a type of area, such as city or village, as a form of disambiguation. The type will appear in the wikilink. local insert = table.insert -- Store this function in a local variable to avoid expensive table lookups. if area then -- If a specific type of area is supplied, put it in the wikilink. insert(text, format(' (%s)', area)) end insert(text, ", ") local sub1dab = args.sub1dab -- Some location names are shared by multiple locations in the same state. This allows for the county to be used to disambiguate the location. if sub1dab then insert(text, format('%s %s, ', sub1dab, sub1name)) end insert(text, region .. '|') if area then -- If a specific type of area is supplied, put a properly-formatted form of it in the wikilink. local linktext = areas[area] insert(text, linktext .. ' of ') end insert(text, sub2 .. ']]') sub2Cell:wikitext(table.concat(text)) -- Concatenate the table's contents and store the result in the cell. end end end end end function units(args) -- This function creates the table cells for the distance. local alt_unit = args.altunit -- Alternate units include California's postmiles. if alt_unit then -- Alternate units take precedence over standard units. local tag = row:tag('th'):attr('scope', 'row'):css('text-align', 'right') -- Create the alternate unit cell. It is treated as a header cell for the row, since it is usually unique within the table. local span = args.auspan or jspan or 1 -- Determine row span ("auspan" = "alt[ernate] unit span"), using global row span argument jspan and 1 as backups, in that order. tag:attr('rowspan', span) -- Apply row span to cell. tag:attr('title', title) -- Apply any type-derived tooltip. tag:wikitext(alt_unit) -- Store the contents of alt_unit in the cell. else -- Numeric distances will be converted to a secondary unit, and both will be displayed. local unit = args.unit -- Numeric distance in the primary unit, or 'none' if no cells are to be displayed if unit ~= 'none' then -- If unit == 'none', don't display any cells. local primary = row:tag('th'):attr('scope', 'row'):css('text-align', 'right') -- Create cell for distance in primary unit. As with alt_unit, this cell is a header cell for the row. local span = args.uspan or jspan or 1 -- Determine row span ("uspan" = "unit span"), using global row span argument jspan and 1 as backups, in that order. primary:attr('rowspan', span) -- Apply row span to cell. primary:attr('title', title) -- Apply any type-derived tooltip. local secondary = row:tag('td'):css('text-align', 'right'):css('background-color', '#f2f2f2'):attr('rowspan', span) -- Create the cell for the distance in the secondary unit, and format it like the cell for the primary unit. secondary:attr('title', title) -- Apply any type-derived tooltip. local unitdef = args.unitdef -- The unit of the supplied distance ('mi' or 'km') primary:wikitext(unit) -- Store the supplied distance in the primary distance cell. secondary:wikitext(conversion(unit, unitdef)) -- Convert the distance into the secondary unit, as determined by unitdef, and store it in the secondary distance cell. local unit2 = args.unit2 -- A second distance may be provided. if unit2 then -- If one is provided, repeat the process. local line = args.line -- A horizontal line may be displayed between the distances. if line then -- If a line is requested, add one to both cells. primary:tag('hr', {selfClosing = true}) secondary:tag('hr', {selfClosing = true}) else -- Otherwise, add an en-dash and line break. primary:wikitext('–'):tag('br', {selfClosing = true}) secondary:wikitext('–'):tag('br', {selfClosing = true}) end primary:wikitext(unit2) -- Add the second distance to the primary distance cell secondary:wikitext(conversion(unit2, unitdef)) -- Convert the second distance into the secondary unit, and add it to the secondary distance cell. end local unit_ref = args.unit_ref -- A reference may be provided for the distance. if unit_ref then primary:wikitext(unit_ref) end -- If one is provided, simply add it to the primary distance cell. end end end function place(args) -- This function generates a cell for places, such as bridges and rest areas local tag = row:tag('td'):css('text-align', 'center') -- Create cell and center-align its future contents local pspan = args.pspan or jspan or 1 -- Determine row span ("pspan" = "place span"), using global row span argument jspan and 1 as backups, in that order tag:attr('rowspan', pspan) -- Apply row span to cell local colspan -- Create local variable to store column span local exit = args[1] -- Whether this table has exit numbers, both old and current exit numbers, or neither local named = args[2] -- Whether this table includes named junctions if exit == 'exit' then -- Calculate column span if named == 'name' then colspan = 4 else colspan = 3 end elseif exit == 'old' then if named == 'name' then colspan = 5 else colspan = 4 end else colspan = 2 end tag:attr('colspan', colspan) -- Apply column span to cell tag:attr('title', title):css('background-color', color) -- Apply any type-derived coloring and tooltip tag:wikitext(args.place) -- Store the place in the cell end function exits(args) -- This function generates table cells for exit and named junction data local exit = args[1] -- Is either 'exit', 'old', or nil local named = args[2] -- Is either 'name' or nil if exit == 'old' then -- Add old exit number cell local oldTag = row:tag('td'):css('text-align', 'center'):css('background-color', '#d3d3d3'):attr('title', 'Former exit number') -- Create cell and properly style it local ospan = args.ospan or jspan or 1 -- Determine row span ("ospan" = "old span"), using global row span argument jspan and 1 as backups, in that order oldTag:attr('rowspan', ospan):wikitext(args.old) -- Apply row span and add old exit number end if exit == 'exit' or exit == 'old' then -- If either is true, add current exit number cell local exitTag = row:tag('td'):css('text-align', 'center') -- Create cell and center-align its contents local espan = args.espan or jspan or 1 -- Determine row span ("espan" = "exit span"), using global row span argument jspan and 1 as backups, in that order exitTag:attr('rowspan', espan) -- Apply row span to cell exitTag:attr('title', title):css('background-color', color) -- Apply any type-derived coloring and tooltip exitTag:wikitext(args.exit) -- Store the exit number in the cell end if named == 'name' then -- This junction list has a junction name column, so a cell must be produced local nameTag = row:tag('td') -- Create a cell for the junction name local namespan = args.namespan or jspan or 1 -- Determine row span, using global row span argument jspan and 1 as backups, in that order nameTag:attr('rowspan', namespan) -- Apply row span to cell nameTag:attr('title', title):css('background-color', color) -- Apply any type-derived coloring and tooltip nameTag:wikitext(args.name) -- Store the junction name in the cell end end function destinations(args) -- This function creates the cells for destinations and notes local destTag = row:tag('td') -- Create destination cell local rcspan = args.rcspan or 1 -- Determine column span ("rcspan" = "road column span"), using 1 as a default destTag:attr('colspan', rcspan) -- Apply column span to cell local rspan = args.rspan or jspan or 1 -- Determine row span ("rspan" = "road span"), using global row span argument jspan and 1 as backups, in that order destTag:attr('rowspan', rspan) -- Apply row span to cell destTag:attr('title', title):css('background-color', color) -- Apply any type-derived coloring and tooltip destTag:wikitext(args.road) -- Store the supplied cell contents local notes = args.notes -- Contents of the notes cell if notes ~= 'none' then -- If the contents equal the string 'none', then no cell will be produced. Otherwise... local notesTag = row:tag('td') -- Create notes cell local nspan = args.nspan or jspan or 1 -- Determine row span ("nspan" = "notes span"), using global row span argument jspan and 1 as backups, in that order notesTag:attr('rowspan', nspan) -- Apply row span to cell notesTag:attr('title', title):css('background-color', color) -- Apply any type-derived coloring and tooltip notesTag:wikitext(notes) -- Store the notes in the cell end end function p._jctint(args) -- This function creates the table row and calls other functions to popluate it. -- This function is accessible from other Lua modules jspan = args.jspan -- Junction span (backup for row span that is applicable to all columns) local argType = args.type -- {{{type}}} argument to determine color and tooltips if argType then -- If a type was passed local typeData = types[string.lower(argType)] -- Retrieve the type data if typeData then color = typeData.color -- Store the color globally title = typeData.jctint -- Store the tooltip globally else -- If there is no type data, add an error category. local page = mw.title.getCurrentTitle() -- Get transcluding page's title local pagename = page.prefixedText -- Extract page's full title as string table.insert(errorMsg, format("[[Category:Jctint template with invalid type|%s]]", pagename)) -- Add error category to error message table. end end local root = mw.html.create() -- Create the root mw.html object row = root:tag('tr'):css('text-align', 'left') -- Create the table row and store it globally locations(args) -- Handle location arguments units(args) -- Handle distance arguments if args.place then -- {{{place}}} spans all columns to the right of the distances place(args) -- Create cell for place else exits(args) -- Handle exit/named junction arguments destinations(args) -- Handle destinations and notes end return tostring(root) .. table.concat(errorMsg) -- Return the HTML code in the mw.html object as a string, plus any error messages end function p.jctint(frame) -- Entry function for {{jctint/core}} return p._jctint(require('Module:Arguments').getArgs(frame)) -- Simply call another function with those arguments to actually create the row end return p -- Return package