Line 411: |
Line 411: |
| -- If no altitude given, use default (zero altitude = sea level). | | -- If no altitude given, use default (zero altitude = sea level). |
| -- Table gives speed of sound in miles per hour at various altitudes: | | -- Table gives speed of sound in miles per hour at various altitudes: |
− | -- altitude = -17,499 to 302,499 feet | + | -- altitude = -17,499 to 402,499 feet |
| -- mach_table[a + 4] = s where | | -- mach_table[a + 4] = s where |
− | -- a = (altitude / 5000) rounded to nearest integer (-3 to 60) | + | -- a = (altitude / 5000) rounded to nearest integer (-3 to 80) |
| -- s = speed of sound (mph) at that altitude | | -- s = speed of sound (mph) at that altitude |
| -- LATER: Should calculate result from an interpolation between the next | | -- LATER: Should calculate result from an interpolation between the next |
Line 423: |
Line 423: |
| 660.1, 660.1, 660.1, 662.0, 664.3, 666.5, 668.9, 671.1, 673.4, 675.6, -- 11 to 20 | | 660.1, 660.1, 660.1, 662.0, 664.3, 666.5, 668.9, 671.1, 673.4, 675.6, -- 11 to 20 |
| 677.9, 683.7, 689.9, 696.0, 702.1, 708.1, 714.0, 719.9, 725.8, 731.6, -- 21 to 30 | | 677.9, 683.7, 689.9, 696.0, 702.1, 708.1, 714.0, 719.9, 725.8, 731.6, -- 21 to 30 |
− | 737.3, 737.7, 737.7, 736.2, 730.5, 724.6, 718.8, 712.9, 707.0, 701.1, -- 31 to 40 | + | 737.3, 737.7, 737.7, 736.2, 730.5, 724.6, 718.8, 712.9, 707.0, 701.0, -- 31 to 40 |
| 695.0, 688.9, 682.8, 676.6, 670.4, 664.1, 657.8, 652.9, 648.3, 643.7, -- 41 to 50 | | 695.0, 688.9, 682.8, 676.6, 670.4, 664.1, 657.8, 652.9, 648.3, 643.7, -- 41 to 50 |
| 639.1, 634.4, 629.6, 624.8, 620.0, 615.2, 613.2, 613.2, 613.2, 613.5, -- 51 to 60 | | 639.1, 634.4, 629.6, 624.8, 620.0, 615.2, 613.2, 613.2, 613.2, 613.5, -- 51 to 60 |
| + | 614.4, 615.3, 616.7, 619.8, 623.4, 629.7, 635.0, 641.1, 650.6, 660.0, -- 61 to 70 |
| + | 672.5, 674.3, 676.1, 677.9, 679.7, 681.5, 683.3, 685.1, 686.8, 688.6, -- 71 to 80 |
| } | | } |
| altitude = altitude or 0 | | altitude = altitude or 0 |
Line 435: |
Line 437: |
| if a < -3 then | | if a < -3 then |
| a = -3 | | a = -3 |
− | elseif a > 60 then | + | elseif a > 80 then |
− | a = 60 | + | a = 80 |
| end | | end |
| return mach_table[a + 4] * 0.44704 -- mph converted to m/s | | return mach_table[a + 4] * 0.44704 -- mph converted to m/s |
Line 442: |
Line 444: |
| -- END: Code required only for built-in units. | | -- END: Code required only for built-in units. |
| ------------------------------------------------------------------------ | | ------------------------------------------------------------------------ |
| + | |
| + | local function add_style(parms, class) |
| + | -- Add selected template style to parms if not already present. |
| + | parms.templatestyles = parms.templatestyles or {} |
| + | if not parms.templatestyles[class] then |
| + | parms.templatestyles[class] = parms.frame:extensionTag({ |
| + | name = 'templatestyles', args = { src = text_code.titles[class] } |
| + | }) |
| + | end |
| + | end |
| + | |
| + | local function get_styles(parms) |
| + | -- Return string of required template styles, empty if none. |
| + | if parms.templatestyles then |
| + | local t = {} |
| + | for _, v in pairs(parms.templatestyles) do |
| + | table.insert(t, v) |
| + | end |
| + | return table.concat(t) |
| + | end |
| + | return '' |
| + | end |
| | | |
| local function get_range(word) | | local function get_range(word) |
Line 1,117: |
Line 1,141: |
| local fracfmt = { | | local fracfmt = { |
| { -- Like {{frac}} (fraction slash). | | { -- Like {{frac}} (fraction slash). |
− | -- 1/2 : sign, numerator, denominator
| + | '<span class="frac" role="math">{SIGN}<span class="num">{NUM}</span>⁄<span class="den">{DEN}</span></span>', -- 1/2 |
− | -- 1+2/3 : signed_wholenumber, numerator, denominator
| + | '<span class="frac" role="math">{SIGN}{WHOLE}<span class="sr-only">+</span><span class="num">{NUM}</span>⁄<span class="den">{DEN}</span></span>', -- 1+2/3 |
− | '<span class="frac nowrap">%s<sup>%s</sup>⁄<sub>%s</sub></span>', | + | style = 'frac', |
− | '<span class="frac nowrap">%s<span class="visualhide"> </span><sup>%s</sup>⁄<sub>%s</sub></span>', | |
| }, | | }, |
− | { -- Like {{sfrac}} (fraction horizontal bar). | + | { -- Like {{sfrac}} (stacked fraction, that is, horizontal bar). |
− | -- 1//2 : sign, numerator, denominator (sign should probably be before the fraction, but then it can wrap, and html is already too long)
| + | '<span class="sfrac tion" role="math">{SIGN}<span class="num">{NUM}</span><span class="sr-only">/</span><span class="den">{DEN}</span></span>', -- 1//2 |
− | -- 1+2//3 : signed_wholenumber, numerator, denominator
| + | '<span class="sfrac" role="math">{SIGN}{WHOLE}<span class="sr-only">+</span><span class="tion"><span class="num">{NUM}</span><span class="sr-only">/</span><span class="den">{DEN}</span></span></span>', -- 1+2//3 |
− | '<span class="sfrac nowrap" style="display:inline-block; vertical-align:-0.5em; font-size:85%%; text-align:center;"><span style="display:block; line-height:1em; padding:0 0.1em;">%s%s</span><span class="visualhide">/</span><span style="display:block; line-height:1em; padding:0 0.1em; border-top:1px solid;">%s</span></span>', | + | style = 'sfrac', |
− | '<span class="sfrac nowrap">%s<span class="visualhide"> </span><span style="display:inline-block; vertical-align:-0.5em; font-size:85%%; text-align:center;"><span style="display:block; line-height:1em; padding:0 0.1em;">%s</span><span class="visualhide">/</span><span style="display:block; line-height:1em; padding:0 0.1em; border-top:1px solid;">%s</span></span></span>', | |
| }, | | }, |
| } | | } |
Line 1,140: |
Line 1,162: |
| wholestr = nil | | wholestr = nil |
| end | | end |
− | if wholestr then | + | local substitute = { |
− | local decorated = with_separator(parms, wholestr) | + | SIGN = negative and MINUS or '', |
− | if negative then | + | WHOLE = wholestr and with_separator(parms, wholestr), |
− | decorated = MINUS .. decorated
| + | NUM = from_en(numstr), |
− | end
| + | DEN = from_en(denstr), |
− | local fmt = fracfmt[style][2]
| + | } |
− | wikitext = format(fmt, decorated, from_en(numstr), from_en(denstr))
| + | wikitext = fracfmt[style][wholestr and 2 or 1]:gsub('{(%u+)}', substitute) |
− | else | |
− | local sign = negative and MINUS or ''
| |
− | wikitext = format(fracfmt[style][1], sign, from_en(numstr), from_en(denstr))
| |
− | end
| |
| if do_spell then | | if do_spell then |
| if negative then | | if negative then |
Line 1,159: |
Line 1,177: |
| end | | end |
| end | | end |
− | wikitext = spell_number(parms, inout, wholestr, numstr, denstr) or wikitext | + | local s = spell_number(parms, inout, wholestr, numstr, denstr) |
| + | if s then |
| + | return s |
| + | end |
| end | | end |
| + | add_style(parms, fracfmt[style].style) |
| return wikitext | | return wikitext |
| end | | end |
Line 1,528: |
Line 1,550: |
| -- v = value of text (text is a number) | | -- v = value of text (text is a number) |
| -- f = true if value is an integer | | -- f = true if value is an integer |
− | -- Input can use en digits or digits in local language, | + | -- Input can use en digits or digits in local language or separators, |
− | -- but no separators, no Unicode minus, and no fraction. | + | -- but no Unicode minus, and no fraction. |
| if text then | | if text then |
| local number = tonumber(to_en(text)) | | local number = tonumber(to_en(text)) |
Line 1,669: |
Line 1,691: |
| end | | end |
| | | |
− | local function range_text(range, want_name, parms, before, after, inout) | + | local function range_text(range, want_name, parms, before, after, inout, options) |
| -- Return before .. rtext .. after | | -- Return before .. rtext .. after |
| -- where rtext is the text that separates two values in a range. | | -- where rtext is the text that separates two values in a range. |
| local rtext, adj_text, exception | | local rtext, adj_text, exception |
| + | options = options or {} |
| if type(range) == 'table' then | | if type(range) == 'table' then |
| -- Table must specify range text for ('off' and 'on') or ('input' and 'output'), | | -- Table must specify range text for ('off' and 'on') or ('input' and 'output'), |
Line 1,689: |
Line 1,712: |
| end | | end |
| end | | end |
− | if rtext == '–' and after:sub(1, #MINUS) == MINUS then | + | if rtext == '–' and (options.spaced or after:sub(1, #MINUS) == MINUS) then |
| rtext = ' – ' | | rtext = ' – ' |
| end | | end |
Line 1,767: |
Line 1,790: |
| -- Return true if successful or return false, t where t is an error message table. | | -- Return true if successful or return false, t where t is an error message table. |
| currency_text = nil -- local testing can hold module in memory; must clear globals | | currency_text = nil -- local testing can hold module in memory; must clear globals |
− | local accept_any_text = {
| |
− | input = true,
| |
− | qid = true,
| |
− | qual = true,
| |
− | stylein = true,
| |
− | styleout = true,
| |
− | tracking = true,
| |
− | }
| |
| if kv_pairs.adj and kv_pairs.sing then | | if kv_pairs.adj and kv_pairs.sing then |
| -- For enwiki (before translation), warn if attempt to use adj and sing | | -- For enwiki (before translation), warn if attempt to use adj and sing |
Line 1,787: |
Line 1,802: |
| local en_name = text_code.en_option_name[loc_name] | | local en_name = text_code.en_option_name[loc_name] |
| if en_name then | | if en_name then |
− | local en_value | + | local en_value = text_code.en_option_value[en_name] |
− | if en_name == '$' or en_name == 'frac' or en_name == 'sigfig' then | + | if en_value == 'INTEGER' then -- altitude_ft, altitude_m, frac, sigfig |
| + | en_value = nil |
| if loc_value == '' then | | if loc_value == '' then |
| add_warning(parms, 2, 'cvt_empty_option', loc_name) | | add_warning(parms, 2, 'cvt_empty_option', loc_name) |
− | elseif en_name == '$' then
| |
− | -- Value should be a single character like "€" for the euro currency symbol, but anything is accepted.
| |
− | currency_text = (loc_value == 'euro') and '€' or loc_value
| |
| else | | else |
| local minimum | | local minimum |
| local number, is_integer = get_number(loc_value) | | local number, is_integer = get_number(loc_value) |
− | if en_name == 'frac' then | + | if en_name == 'sigfig' then |
| + | minimum = 1 |
| + | elseif en_name == 'frac' then |
| minimum = 2 | | minimum = 2 |
| if number and number < 0 then | | if number and number < 0 then |
Line 1,804: |
Line 1,819: |
| end | | end |
| else | | else |
− | minimum = 1 | + | minimum = -1e6 |
| end | | end |
| if number and is_integer and number >= minimum then | | if number and is_integer and number >= minimum then |
| en_value = number | | en_value = number |
| else | | else |
− | add_warning(parms, 1, (en_name == 'frac' and 'cvt_bad_frac' or 'cvt_bad_sigfig'), loc_name .. '=' .. loc_value) | + | local m |
| + | if en_name == 'frac' then |
| + | m = 'cvt_bad_frac' |
| + | elseif en_name == 'sigfig' then |
| + | m = 'cvt_bad_sigfig' |
| + | else |
| + | m = 'cvt_bad_altitude' |
| + | end |
| + | add_warning(parms, 1, m, loc_name .. '=' .. loc_value) |
| end | | end |
| end | | end |
− | elseif accept_any_text[en_name] then | + | elseif en_value == 'TEXT' then -- $, input, qid, qual, stylein, styleout, tracking |
| en_value = loc_value ~= '' and loc_value or nil -- accept non-empty user text with no validation | | en_value = loc_value ~= '' and loc_value or nil -- accept non-empty user text with no validation |
− | if en_name == 'input' then | + | if not en_value and (en_name == '$' or en_name == 'qid' or en_name == 'qual') then |
| + | add_warning(parms, 2, 'cvt_empty_option', loc_name) |
| + | elseif en_name == '$' then |
| + | -- Value should be a single character like "€" for the euro currency symbol, but anything is accepted. |
| + | currency_text = (loc_value == 'euro') and '€' or loc_value |
| + | elseif en_name == 'input' then |
| -- May have something like {{convert|input=}} (empty input) if source is an infobox | | -- May have something like {{convert|input=}} (empty input) if source is an infobox |
| -- with optional fields. In that case, want to output nothing rather than an error. | | -- with optional fields. In that case, want to output nothing rather than an error. |
Line 1,820: |
Line 1,848: |
| end | | end |
| else | | else |
− | en_value = text_code.en_option_value[en_name][loc_value] | + | en_value = en_value[loc_value] |
| if en_value and en_value:sub(-1) == '?' then | | if en_value and en_value:sub(-1) == '?' then |
| en_value = en_value:sub(1, -2) | | en_value = en_value:sub(1, -2) |
Line 2,172: |
Line 2,200: |
| end | | end |
| if in_unit_table.builtin == 'mach' then | | if in_unit_table.builtin == 'mach' then |
− | -- As with old template, a number following Mach as the input unit is the altitude, | + | -- As with old template, a number following Mach as the input unit is the altitude. |
− | -- and there is no way to specify an altitude for the output unit. | + | -- That is deprecated: should use altitude_ft=NUMBER or altitude_m=NUMBER. |
− | -- Could put more code in this function to get any output unit and check for | + | local success, info |
− | -- an altitude following that unit. | + | success = tonumber(parms[i]) -- this will often work and will give correct result for values like 2e4 without forcing output scientific notation |
− | local success, info = extract_number(parms, parms[i], false, true) | + | if success then |
| + | info = { value = success } |
| + | else |
| + | success, info = extract_number(parms, parms[i], false, true) |
| + | end |
| if success then | | if success then |
| i = i + 1 | | i = i + 1 |
Line 2,404: |
Line 2,436: |
| end | | end |
| if in_builtin == 'mach' or out_builtin == 'mach' then | | if in_builtin == 'mach' or out_builtin == 'mach' then |
− | local adjust | + | -- Should check that only one altitude is given but am planning to remove |
| + | -- in_current.altitude (which can only occur when Mach is the input unit), |
| + | -- and out_current.altitude cannot occur. |
| + | local alt = parms.altitude_ft or in_current.altitude |
| + | if not alt and parms.altitude_m then |
| + | alt = parms.altitude_m / 0.3048 -- 1 ft = 0.3048 m |
| + | end |
| + | local spd = speed_of_sound(alt) |
| if in_builtin == 'mach' then | | if in_builtin == 'mach' then |
− | inscale = speed_of_sound(in_current.altitude) | + | inscale = spd |
− | adjust = outscale / 0.1 | + | return invalue * (inscale / outscale) |
− | else
| |
− | outscale = speed_of_sound(out_current.altitude)
| |
− | adjust = 0.1 / inscale
| |
| end | | end |
| + | outscale = spd |
| + | local adjust = 0.1 / inscale |
| return true, { | | return true, { |
| outvalue = invalue * (inscale / outscale), | | outvalue = invalue * (inscale / outscale), |
Line 2,611: |
Line 2,649: |
| show = format('%.0f', floor((outvalue / n) + 0.5) * n) | | show = format('%.0f', floor((outvalue / n) + 0.5) * n) |
| end | | end |
| + | elseif in_current.builtin == 'mach' then |
| + | local sigfig = info.clean:gsub('^[0.]+', ''):gsub('%.', ''):len() + 1 |
| + | show, exponent = make_sigfig(outvalue, sigfig) |
| else | | else |
| local inclean = info.clean | | local inclean = info.clean |
Line 3,234: |
Line 3,275: |
| -- For simplicity and because more not needed, handle one range item only. | | -- For simplicity and because more not needed, handle one range item only. |
| local prefix2 = make_id(parms, 2, first_unit) .. ' ' | | local prefix2 = make_id(parms, 2, first_unit) .. ' ' |
− | result = range_text(range[1], want_name, parms, result, prefix2 .. valinfo[2].show, 'in') | + | result = range_text(range[1], want_name, parms, result, prefix2 .. valinfo[2].show, 'in', {spaced=true}) |
| end | | end |
| return preunit .. result | | return preunit .. result |
Line 3,324: |
Line 3,365: |
| if range then | | if range then |
| -- For simplicity and because more not needed, handle one range item only. | | -- For simplicity and because more not needed, handle one range item only. |
− | result = range_text(range[1], want_name, parms, result, prefix .. valinfo[2].show, inout) | + | result = range_text(range[1], want_name, parms, result, prefix .. valinfo[2].show, inout, {spaced=true}) |
| end | | end |
| return preunit .. result | | return preunit .. result |
Line 3,530: |
Line 3,571: |
| local success, result2 = make_result(valinfo[i+1]) | | local success, result2 = make_result(valinfo[i+1]) |
| if not success then return false, result2 end | | if not success then return false, result2 end |
− | result = range_text(range[i], want_name, parms, result, result2, inout) | + | result = range_text(range[i], want_name, parms, result, result2, inout, {spaced=true}) |
| end | | end |
| end | | end |
Line 3,660: |
Line 3,701: |
| wikitext = wikitext .. parms.warnings | | wikitext = wikitext .. parms.warnings |
| end | | end |
− | return true, wikitext, out_unit_table | + | return true, get_styles(parms) .. wikitext, out_unit_table |
| end | | end |
| | | |