Module:Unicode chart and Module:Unicode chart/sandbox: Difference between pages
Appearance
(Difference between pages)
Content deleted Content added
Cobaltcigs (talk | contribs) several changes to range handling to allow, among other things, referring to predefined subsets |
No edit summary |
||
Line 1: | Line 1: | ||
local p = {} |
|||
local mArguments = require('Module:Arguments') |
|||
local |
local getArgs = require('Module:Arguments').getArgs |
||
local yesno = require('Module:Yesno') |
|||
local mRedirect = require('Module:Redirect') |
|||
local mUnicode = require('Module:Unicode data') |
local mUnicode = require('Module:Unicode data') |
||
local mAge = require('Module:Unicode data/age') |
|||
local mAliases = require('Module:Unicode data/aliases') |
|||
local mBlocks = require('Module:Unicode data/blocks') |
|||
local mCategory = require('Module:Unicode data/category') |
local mCategory = require('Module:Unicode data/category') |
||
local mControl = require('Module:Unicode data/control') |
|||
local mScripts = require('Module:Unicode data/scripts') |
|||
local mVersion = require('Module:Unicode data/version') |
local mVersion = require('Module:Unicode data/version') |
||
local |
local mAliases = require('Module:Unicode data/aliases') |
||
local mDisplay = require('Module:Unicode chart/display') |
|||
local frame |
|||
local mSubsets = require('Module:Unicode chart/subsets') |
|||
local p = {} |
|||
local args = {} |
|||
local config = { |
|||
useFontCss = true, |
|||
showRefs = true, |
|||
infoMode = false, |
|||
} |
|||
------------------- |
|||
local refGrammar = { |
|||
-- General settings |
|||
order = { "white", "combining", "control", "format", "reserved", "nonchar", "skip" }, |
|||
------------------- |
|||
white = { |
|||
local pdfLink = "[https://www.unicode.org/charts/PDF/%s.pdf" |
|||
format = 'White area%s within light green cell%s show%s %s of %sotherwise invisible [[whitespace character]]%s.', |
|||
.. " Official Unicode Consortium code chart] (PDF)" |
|||
singular = { '', '', 's', 'the size', 'an ', '' }, |
|||
local cellType = { |
|||
plural = { 's', 's', '', 'sizes', '', 's' }, |
|||
count = 0, |
|||
}, |
|||
combining = { |
|||
format = 'Yellow cell%s with [[dotted circle]]%s (◌) indicate%s %s[[combining character]]%s.', |
|||
singular = { '', '', 's', 'a ', '' }, |
|||
plural = { 's', 's', '', '','s' }, |
|||
count = 0, |
|||
}, |
|||
control = { |
|||
format = 'Light blue cell%s indicate%s %snon-printable [[control character]]%s.', |
|||
singular = { '', 's', 'a ', '' }, |
|||
plural = { 's', '', '', 's' }, |
|||
count = 0, |
|||
}, |
|||
format = { |
|||
format = 'Pink cell%s indicate%s %s[[format character]]%s.', |
|||
singular = { '', 's', 'a ', '' }, |
|||
plural = { 's', '', '', 's' }, |
|||
count = 0, |
|||
}, |
|||
reserved = { |
reserved = { |
||
note = "Grey areas indicate non-assigned code points", |
|||
flag = false |
|||
singular = { '', 's', 'an ', '' }, |
|||
}, |
|||
plural = { 's', '', '', 's' }, |
|||
noncharacter = { |
|||
count = 0, |
|||
note = "Black areas indicate [[Universal Character Set characters#Noncharacters|noncharacters]] (code points that are guaranteed never to be assigned as encoded characters in the Unicode Standard)", |
|||
}, |
|||
flag = false |
|||
nonchar = { |
|||
format = 'Black cell%s indicate%s %s[[noncharacter]]%s (code point%s that %s guaranteed never to be assigned as %sencoded character%s in the Unicode Standard).', |
|||
singular = { '','s','a ', '', '', 'is','an ', '' }, |
|||
plural = { 's','', '','s','s','are', '','s' }, |
|||
count = 0, |
|||
}, |
|||
skip = { |
|||
format = 'Black horizontal line%s indicate%s non-consecutive rows.', |
|||
singular = { '', 's' }, |
|||
plural = { 's', '' }, |
|||
count = 0, |
|||
}, |
|||
} |
} |
||
} |
|||
local |
local hardcodedNumberedAbbrSets = { |
||
-- Block: Variation Selectors |
|||
local err = { |
|||
{first = 0xFE00, last = 0xFE0F, str = "VS<br>", startNum = 1}, |
|||
format = function(...) return error(string.format(...), 0) end, |
|||
-- Block: Variation Selectors Supplement |
|||
blockName = 'Unrecognized block name "%s" does not match those defined in [[Module:Unicode data/blocks]]', |
|||
{first = 0xE0100, last = 0xE01EF, str = "VS<br>", startNum = 17}, |
|||
refGarbage = 'Refs contain non-ref content: "%s"', |
|||
-- Block: Sutton SignWriting |
|||
badRange = 'Invalid range "%s" specified. Ranges must match [[regular expression]] <code>^[0-9A-F]+(?:[-–][0-9A-F]+)?$</code>', |
|||
-- SIGNWRITING FILL MODIFIER-2 -> SW F# |
|||
noRange = 'Please specify a valid block name, range of code points, or named subset', |
|||
{first = 0x1DA9B, last = 0x1DA9F, str = 'SW<br>F', startNum = 2}, |
|||
badSubset = 'Invalid subset "%s" specified', |
|||
-- Block: Sutton SignWriting |
|||
} |
|||
-- SIGNWRITING ROTATION MODIFIER-2 -> SW R# |
|||
{first = 0x1DAA1, last = 0x1DAAF, str = 'SW<br>R', startNum = 2}, |
|||
} |
|||
local specialFormatSets = { |
|||
function debug(...) |
|||
--Unicode block: Tags |
|||
local a = {...} |
|||
--tag for character -> character |
|||
if type(a[1]) ~= "string" then mw.log(a[1]) return end |
|||
{first = 0xE0021, last = 0xE007E, |
|||
local _,c = string.gsub(string.gsub(a[1], "%%%%", ""), "%%", "") |
|||
func = function(codepoint, abbr) |
|||
for i = 1,math.max(#a, c+1) do |
|||
return '&#x'.. string.format("%04X", (codepoint - 0xE0000)) .. ';' |
|||
if (type(a[i]) == "nil" or type(a[i]) == "boolean") then a[i] = tostring(a[i]) end |
|||
end |
|||
}, |
|||
} |
|||
------------------------- |
|||
-- pseudo-object oriented |
|||
------------------------- |
|||
function newCodepoint(x) |
|||
if type(x) == "string" then |
|||
return { |
|||
hex = x, |
|||
int = tonumber(x, 16) |
|||
} |
|||
elseif type(x) == "number" then |
|||
return { |
|||
int = x, |
|||
hex = string.format("%04X", x) |
|||
} |
|||
end |
end |
||
return mw.log(string.format(unpack(a))) |
|||
end |
end |
||
------------------------- |
|||
table.concat2 = function(t1,t2) for i=1,#t2 do t1[#t1+1] = t2[i] end return t1 end |
|||
-- Sundry small functions |
|||
table.last = function(t) if t then return t[#t] else return nil end end |
|||
------------------------- |
|||
local function expandTemplate(template, argslist) |
|||
return frame:expandTemplate{ |
|||
string.formatAll = function(fmt, t) |
|||
title = template, |
|||
for i=1,#t do t[i] = string.format(fmt, t[i]) end |
|||
args = argslist |
|||
return t |
|||
} |
|||
end |
end |
||
function getUtf8(n) |
|||
local t = {} |
|||
for b in mw.ustring.char(n):gmatch('.') do table.insert(t, b:byte()) end |
|||
return t |
|||
end |
|||
function getUtf16(n) |
|||
if(n < 0 or n > 0x10FFFF) then return nil end |
|||
if(n >= 0xD800 and n <= 0xDFFF) then return nil end |
|||
if(n < 0x10000) then return { n } end |
|||
local u = (n - 0x10000) |
|||
local low = (u % 0x400) |
|||
local high = (u - low) / 0x400 |
|||
return { 0xD800 + high, 0xDC00 + low } |
|||
end |
|||
function getUtf16toStr(n) |
|||
t = getUtf16(n) |
|||
for i=1,#t do t[i] = string.format("0x%04X", t[i]) end |
|||
return t |
|||
end |
|||
function getUtf8toStr(n) return string.formatAll("0x%02X", getUtf8(n) ) end |
|||
function getUtf16toStr(n) return string.formatAll("0x%04X", getUtf16(n)) end |
|||
function |
local function fromHex(hexStr) |
||
return tonumber(hexStr, 16) |
|||
if(b) then return {first=math.min(a,b),last=math.max(a,b)} else return {first=a,last=a} end |
|||
end |
|||
function rangeContains(r, n) return (n >= r.first and n <= r.last) end |
|||
function rangeCombine(r1,r2) return {first=math.min(r1.first,r2.first), last=math.max(r1.last,r2.last)} end |
|||
function rangesMergeable(r1,r2) |
|||
if not r1 or not r2 then return false end |
|||
return rangeContains(r1, r2.first-1) or rangeContains(r1, r2.last+1) or |
|||
rangeContains(r2, r1.first-1) or rangeContains(r2, r1.last+1) |
|||
end |
|||
function rangeSort(r1,r2) |
|||
if r1 and not r2 then return true end |
|||
if not r1 then return false end |
|||
if r1.first == r2.first then return r1.last < r2.last end |
|||
return r1.first < r2.first |
|||
end |
end |
||
local function splitColonList(strList) |
|||
function parseHex(s) if s then return tonumber(s,16) else return nil end end |
|||
local tab = {} |
|||
function parseRanges(str) |
|||
local segments = mw.text.split(strList, '[;\n\t]') |
|||
local r = {} |
|||
for _,v in pairs(segments) do |
|||
str = str:upper():gsub("AND", ",") --avoid parsing A and D as single control chars in row U+000x, whoops |
|||
local tmp = mw.text.split(v, ':') |
|||
for x in mw.ustring.gmatch(str, "[%dA-FUX%+%-]+") do |
|||
if tmp[1] and tmp[2] then |
|||
local a,b = mw.ustring.match(x, "^[UX0%+%-]*([%dA-F]+)[-–][UX0%+%-]*([%dA-F]+)$") |
|||
tab[fromHex(tmp[1])] = mw.text.trim(tmp[2]) |
|||
if(a and b) then |
|||
table.insert(r, makeRange(parseHex(a),parseHex(b))) |
|||
else |
|||
local c = mw.ustring.match(x, "^[UX0%+%-]*([%dA-F]+)$") |
|||
if c then |
|||
table.insert(r, makeRange(parseHex(c))) |
|||
else |
|||
err.format(err.badRange, x) |
|||
end |
|||
end |
end |
||
end |
end |
||
return tab |
|||
for i = #r,2,-1 do for j = i-1,1,-1 do if rangesMergeable(r[i], r[j]) then |
|||
r[j] = rangeCombine(r[i], r[j]) r[i] = nil |
|||
end end end |
|||
r2 = {} |
|||
for k,v in pairs(r) do table.insert(r2,v) end |
|||
table.sort(r2, rangeSort) |
|||
return r2 |
|||
end |
end |
||
local function getCategory(codepoint) |
|||
-- Official way to match property values that are strings (including block names): |
|||
local category = mUnicode.lookup_control(codepoint.int) |
|||
-- Ignore case, whitespace, underscore ('_'), hyphens, and any initial prefix string "is". |
|||
if category ~= "unassigned" then |
|||
-- http://www.unicode.org/reports/tr44/#UAX44-LM3 |
|||
return category |
|||
local function propertyValueKey(val) |
|||
elseif mUnicode.is_noncharacter(codepoint.int) then |
|||
return val:lower():gsub('^is', ''):gsub('[-_%s]+', '') |
|||
return "noncharacter" |
|||
else |
|||
return "reserved" |
|||
end |
|||
end |
end |
||
function getDefaultRange(blockName) |
|||
local function getAliasValues(n, key) |
|||
if not blockName then return nil end |
|||
local tbl = {} |
|||
blockName = propertyValueKey(blockName) |
|||
if mAliases[n] then |
|||
for i,b in ipairs(mBlocks) do |
|||
for i,t in ipairs(mAliases[n]) do |
|||
if blockName == propertyValueKey(b[3]) then return makeRange(b[1],b[2]) end |
|||
if(not key or t[1] == key) then |
|||
table.insert(tbl, t[2]) |
|||
end |
|||
end |
|||
end |
end |
||
return tbl |
|||
end |
end |
||
--------------------- |
|||
function getAge(n) |
|||
-- A single unicode cell within the table |
|||
local a = mAge.singles[n] |
|||
--------------------- |
|||
if(a) then return a end |
|||
local function getCellAbbr(codepoint, category, args) |
|||
for k,v in pairs(mAge.ranges) do |
|||
local function getHardcodedNumberedAbbr(codepoint) |
|||
if n >= v[1] and n <= v[2] then return v[3] end |
|||
for key, value in pairs(hardcodedNumberedAbbrSets) do |
|||
if codepoint.int >= value.first |
|||
and codepoint.int <= value.last then |
|||
return value.str .. (codepoint.int - value.first + value.startNum) |
|||
end |
|||
end |
|||
return nil |
|||
end |
|||
--for key, value in pairs(specialFormatSets) do |
|||
-- if codepoint.int >= value.first |
|||
-- and codepoint.int <= value.last then |
|||
-- return value.func(codepoint.int, alias) |
|||
-- end |
|||
--end |
|||
local function getAliasAbbr(codepoint) |
|||
local tbl = getAliasValues(codepoint.int, "abbreviation") |
|||
return tbl[1] or nil |
|||
end |
|||
local function abbrFromString(codepoint, args) |
|||
local abbr = "" |
|||
local name = mUnicode.lookup_name(codepoint.int) |
|||
local words = mw.text.split(name, ' ') |
|||
for _,w in pairs(words) do |
|||
abbr = abbr .. string.sub(w, 1, 1) |
|||
end |
|||
return abbr |
|||
end |
end |
||
return nil |
|||
end |
|||
function getCategory(n) |
|||
local cc = mUnicode.lookup_category(n) |
|||
local cat = mCategory.long_names[cc] |
|||
if cat then return string.gsub(string.lower(cat), "_", " ") else return nil end |
|||
end |
|||
--override |
|||
function getControlAbbrs(n) return getAliasValues(n, "abbreviation") end |
|||
if (args['abbr_sub'] and args['abbr_sub'][codepoint.int]) then |
|||
function getControlAliases(n) return table.concat2(getAliasValues(n, "control"), getAliasValues(n, "figment")) end |
|||
return args['abbr_sub'][codepoint.int] |
|||
end |
|||
function getAliasValues(n, key) |
|||
--exception listed at top |
|||
local b,r = mAliases[n], {} |
|||
local abbr1 = getHardcodedNumberedAbbr(codepoint) |
|||
if b then for i,t in ipairs(b) do |
|||
if abbr1 then return abbr1 end |
|||
--abbr on list |
|||
end end |
|||
local abbr2 = getAliasAbbr(codepoint) |
|||
return r |
|||
if abbr2 then return abbr2 end |
|||
end |
|||
--make own abbr |
|||
if category == "control" or category == "format" then |
|||
function getAnchorId(n) return string.format("info-%04X", n) end |
|||
return '<span class="red">' .. abbrFromString(codepoint) .. '</span>' |
|||
function getTarget(n) |
|||
end |
|||
if(config.infoMode) then return "#"..getAnchorId(n) end |
|||
local t = getParamNx("link", n, true) |
|||
if(t=="yes") then t = char end |
|||
--"ifexist" is a deleted feature, now recognized equal to "no" to avoid linking to the article [[Ifexist]], which incidentally doesn't exist. |
|||
if(t=="no" or t=="ifexist") then t = nil end |
|||
if(t=="wikt") then t = ":wikt:"..mw.ustring.char(n) end |
|||
return t |
|||
end |
|||
function getNamedEntity(n) |
|||
local e = mEntities[n] |
|||
if e then return string.gsub(e, "&", "&") else return nil end |
|||
end |
|||
function getEntities(n) |
|||
local entH = getNamedEntity(n) |
|||
local entN = string.format('&#%d;', n) |
|||
local entXN = string.format('&#x%X;', n) |
|||
local t = {} |
|||
if(entH) then table.insert(t, entH) end |
|||
table.insert(t, entN) |
|||
table.insert(t, entXN) |
|||
return t |
|||
end |
|||
function isControl(n) return mUnicode.lookup_control(n) == "control" end |
|||
function isFormat(n) return mUnicode.lookup_control(n) == "format" end |
|||
function isBadTitle(str) |
|||
if str == nil then return true end |
|||
if type(str) == "number" then str = mw.ustring.char(str) end |
|||
if not mUnicode.is_valid_pagename(str) then return true end |
|||
if mw.ustring.match(str, "[\<\>]") then return true end |
|||
if #str == 1 and mw.ustring.match(str, "[\/\.\:\_̸]") then return true end |
|||
return false |
return false |
||
end |
end |
||
function |
local function aliasesStr(codepoint) |
||
local aliasStr = "" |
|||
if(not config.showRefs or mVersion == nil or mVersion == '') then return '' |
|||
if mAliases[codepoint.int] then |
|||
else return string.format('<ref name="version">As of [[Unicode#Versions|Unicode version]] %s.</ref>', mw.text.nowiki(mVersion)) end |
|||
for i,t in ipairs(mAliases[codepoint.int]) do |
|||
end |
|||
aliasStr = aliasStr .. " (alias " .. t[2] .. ")" |
|||
function makeAutoRefs() |
|||
if not config.showRefs then return '' end |
|||
local refs = {} |
|||
for i,refType in ipairs(refGrammar.order) do |
|||
local g = refGrammar[refType] |
|||
local refText = nil |
|||
if(g.count == 1) then refText = string.format(g.format, unpack(g.singular)) end |
|||
if(g.count >= 2) then refText = string.format(g.format, unpack(g.plural)) end |
|||
if(refText) then |
|||
table.insert(refs, string.format('<ref name="%s">%s</ref>', refType, refText)) |
|||
end |
end |
||
end |
end |
||
return |
return aliasStr |
||
end |
end |
||
local function linkChar(unicodeChar, codepoint, args) |
|||
--TODO: remove any garbage around/between refs and downgrade this to a warning |
|||
if (args['link_sub'] and args['link_sub'][codepoint.int]) then |
|||
function sanitizeUserRefs(refTxt) |
|||
return '[[' .. args['link_sub'][codepoint.int] |
|||
if not config.showRefs then return '' end |
|||
.. '|' .. unicodeChar .. ']]' |
|||
local trim1 = mw.text.killMarkers(refTxt) |
|||
elseif args['link'] == "wiki" then |
|||
local trim2 = mw.ustring.gsub(trim1, '%s', '') |
|||
local redir = mRedirect.luaMain(unicodeChar, false) |
|||
if string.len(trim2) > 0 then err.format(err.refGarbage, mw.text.nowiki(trim1)) |
|||
-- '[[' .. redir .. '|' .. unicodeChar .. ']]' |
|||
else return refTxt end |
|||
return expandTemplate('Link if exists', {unicodeChar}) |
|||
end |
|||
elseif args['link'] == "wikt" then |
|||
function makeSpan(str, title, repl) |
|||
return '[[wikt:' .. unicodeChar .. '|' .. unicodeChar .. ']]' |
|||
local c,t = '','' |
|||
if title then t = string.format(' title="%s"', title) end |
|||
if repl then |
|||
local s,x = mw.ustring.gsub(str, '%s+', '\n') |
|||
if x > 0 then c = string.format(' class="small-%s"', x) str = s end |
|||
end |
end |
||
return string.format('<span %s%s>%s</span>', c, t, str) |
|||
end |
|||
function makeLink(a, b) |
|||
if not a or (isBadTitle(a) and not config.infoMode) then return (b or '') end |
|||
if not b then b = a end |
|||
return string.format("[[%s|%s]]",a,b) |
|||
end |
end |
||
function |
local function createCell(cell, codepoint, args) |
||
-- sub functions |
|||
if not mAliases[n] then return '' end |
|||
local |
local function emptyCell(categoryStr) |
||
cellType[categoryStr].flag = true |
|||
table.insert(t, '<div class="alias"><ul>') |
|||
-- flag[categoryStr] = true |
|||
for k,v in ipairs(mAliases[n]) do |
|||
local tr = string.format('<li class="%s">%s</li>', v[1], v[2]) |
|||
table.insert(t, tr) |
|||
end |
end |
||
local function abbrCell(abbr) |
|||
table.insert(t, '</ul></div>') |
|||
cell:addClass("abbr-cell") |
|||
return table.concat(t) |
|||
cell:tag("div"):addClass("abbr-box"):wikitext(abbr) |
|||
end |
|||
function makeDivUl(t, class) return makeDiv(makeUl(t), class) end |
|||
function makeUl(t, class) |
|||
if not t then return '' end |
|||
if class then class = string.format(' class="%s"', class) else class = '' end |
|||
return string.format('<ul%s><li>%s</li></ul>', class, table.concat(t, '</li><li>')) |
|||
end |
|||
function makeDiv(s, class) |
|||
if not s or string.len(s) == 0 then return '' end |
|||
if class then class = string.format(' class="%s"', class) else class = '' end |
|||
return string.format('<div%s>%s</div>', class, s) |
|||
end |
|||
function makeInfoRow(info) |
|||
local alii = makeAliasList(info.n) |
|||
local html = makeDivUl(getEntities(info.n), 'html') |
|||
local utf8 = makeDivUl(getUtf8toStr(info.n), 'utf8') |
|||
local utf16 = makeDivUl(getUtf16toStr(info.n), 'utf16') |
|||
local age = getAge(info.n) |
|||
if(age) then age = string.format('<div class="age">Introduced in Unicode version %s.</div>', age) else age = '' end |
|||
if(info.category == 'control') then info.name = mw.text.nowiki('<control>') end |
|||
if(info.category == 'space separator') then info.cBox = ' box' end |
|||
local class = '' |
|||
if config.useFontCss then class = class..'script-'..info.sCode end |
|||
local charInfo = '<div class="char">'..table.concat({utf8, utf16, html, age})..'</div>' |
|||
local titleBarFmt = '<div><div class="title">%s %s</div><div class="category">%s</div></div>' |
|||
local titleBar = string.format(titleBarFmt, info.uPlus, info.name, info.category) |
|||
local fmt = '<tr class="info-row" id="%s"><th class="thumb %s%s">%s</th><td colspan="16" class="info">%s%s%s</td></tr>' |
|||
return string.format(fmt, getAnchorId(info.n), class, info.cBox, info.display, titleBar, alii, charInfo) |
|||
end |
|||
function getParamNx(key, n, c) |
|||
local key4 = string.format("%s_%04X", key, n) |
|||
if args[key4] then return args[key4] end |
|||
if c then |
|||
local key3 = string.format("%s_%03Xx", key, math.floor(n/16)) |
|||
return args[key3] or args[key] |
|||
end |
end |
||
return nil |
|||
-- main func begins |
|||
end |
|||
local category = getCategory(codepoint) |
|||
cell:addClass(category) |
|||
function makeGridCell(n, charMask) |
|||
local |
local abbr = getCellAbbr(codepoint, category, args) |
||
local char = mw.ustring.char(n) |
|||
if category == "reserved" or category == "noncharacter" then |
|||
local cfFmt = '<td title="%s" class="char%s"><div>\n%s\n</div></td>' |
|||
emptyCell(category) |
|||
local isControlN, isFormatN = isControl(n), isFormat(n) |
|||
elseif abbr then |
|||
local charName = table.last(getControlAliases(n)) or mUnicode.lookup_name(n) |
|||
abbrCell(abbr) |
|||
if isControlN then charName = charName or "<control>" end |
|||
local cBox = '' |
|||
local masterListDisplay = mDisplay[n] |
|||
if masterListDisplay then cBox = ' box' end |
|||
local display = masterListDisplay or char |
|||
local title = uPlus..' '..charName |
|||
if isControlN or isFormatN then display = makeSpan(display, title, true) end |
|||
local sCode = nil |
|||
if config.useFontCss then sCode = mUnicode.lookup_script(n) end |
|||
--default dir="ltr" need not be specified |
|||
local sDir = '' |
|||
if mUnicode.is_rtl(char) then sDir = ' dir="rtl"' end |
|||
local sClass = "" |
|||
local linkThis = getTarget(n) |
|||
local cell = '' |
|||
local generateInfoPanel = true |
|||
--3 types of empty cells |
|||
if(not charMask[n]) then |
|||
--fill extra spaces surrounding an irregular (non-multiple of 16) range of displayed chars |
|||
cell = '<td class="excluded"></td>' |
|||
generateInfoPanel = false |
|||
elseif string.match(charName, '<reserved') then |
|||
refGrammar.reserved.count = refGrammar.reserved.count + 1 |
|||
cell = string.format('<td title="%s RESERVED" class="reserved"></td>', uPlus) |
|||
generateInfoPanel = false |
|||
elseif string.match(charName, '<noncharacter') then |
|||
refGrammar.nonchar.count = refGrammar.nonchar.count + 1 |
|||
cell = string.format('<td title="%s NONCHARACTER" class="nonchar"></td>', uPlus) |
|||
generateInfoPanel = false |
|||
--actual chars |
|||
elseif mUnicode.is_whitespace(n) then |
|||
refGrammar.white.count = refGrammar.white.count + 1 |
|||
local cellFmt = '<td title="%s" class="char whitespace"%s><div>\n%s\n</div></td>' |
|||
display = makeSpan(display, title, false) |
|||
cell = string.format(cellFmt, title, sDir, makeLink(linkThis, makeSpan(char, title, false))) |
|||
elseif isControlN then |
|||
refGrammar.control.count = refGrammar.control.count + 1 |
|||
cell = string.format(cfFmt, title, " control box", makeLink(linkThis, display)) |
|||
elseif isFormatN then |
|||
refGrammar.format.count = refGrammar.format.count + 1 |
|||
cell = string.format(cfFmt, title, " format box", makeLink(linkThis, display)) |
|||
else |
else |
||
local unicodeChar = '&#x'.. codepoint.hex .. ';' |
|||
if sCode then sClass = sClass..string.format(' script-%s', sCode) end |
|||
unicodeChar = linkChar(unicodeChar, codepoint, args) or unicodeChar |
|||
sClass = sClass..cBox |
|||
if args['suffix'] and args['suffix'][codepoint.int] then |
|||
isCombining = mUnicode.is_combining(n) |
|||
unicodeChar = unicodeChar |
|||
if isCombining then |
|||
.. '&#x' .. args['suffix'][codepoint.int] .. ';' |
|||
refGrammar.combining.count = refGrammar.combining.count + 1 |
|||
cell:addClass("modified") |
|||
sClass = sClass.." combining" |
|||
display = "◌"..char |
|||
end |
end |
||
if args['wrapper'] then |
|||
display = makeSpan(display, title, true) |
|||
unicodeChar = expandTemplate(args['wrapper'], {unicodeChar}) |
|||
local cellFmt = '<td title="%s" class="char%s"%s><div>\n%s\n</div></td>' |
|||
elseif args['font'] then |
|||
cell = string.format(cellFmt, title, sClass, sDir, makeLink(linkThis,display)) |
|||
cell:css("font-family", "'" .. args['font'] .. "'") |
|||
end |
|||
--unicodeChar = tostring( |
|||
if(config.infoMode and generateInfoPanel) then |
|||
-- mw.html.create("div") |
|||
local printable = mUnicode.is_printable(n) |
|||
-- :css("font-family", "'" .. args['font'] .. "'") |
|||
local category = getCategory(n) |
|||
-- :wikitext(unicodeChar) |
|||
local info = { |
|||
--) |
|||
char = char, |
|||
name = charName, |
|||
sCode = sCode, |
|||
display = display, |
|||
uPlus = uPlus, |
|||
printable = printable, |
|||
category = category, |
|||
cBox = cBox, |
|||
} |
|||
table.insert(infoTable, makeInfoRow(info)) |
|||
end |
|||
return cell |
|||
end |
|||
function getMask(ranges) |
|||
local ch,r = {},{} |
|||
for i,range in ipairs(ranges) do |
|||
for n=range.first,range.last do |
|||
ch[n] = true |
|||
r[n-n%16] = true |
|||
end |
end |
||
cell:wikitext(unicodeChar) |
|||
end |
end |
||
local |
local name = mUnicode.lookup_name(codepoint.int) |
||
name = string.match(name, "<([a-z]+)-%w+>") or name |
|||
for i,x in pairs(r) do table.insert(row, i) end |
|||
cell:attr("title", |
|||
table.sort(row) |
|||
'U+' .. codepoint.hex .. |
|||
return ch,row |
|||
': ' .. name |
|||
.. aliasesStr(codepoint) |
|||
) |
|||
end |
end |
||
--------------------- |
|||
function p.main( frame ) |
|||
-- For loops creating the grid of cells |
|||
for k, v in pairs(mArguments.getArgs(frame)) do args[k] = v end |
|||
--------------------- |
|||
config.infoMode = (args["info"] or 'no'):lower() ~= "no" |
|||
local function createTableBody(body, rangeStart, rangeEnd, args) |
|||
config.useFontCss = (args["fonts"] or args["font"] or 'yes'):lower() ~= "no" |
|||
--0 through F label row |
|||
local userRefs = args["refs"] or args["notes"] or args["ref"] or args["note"] or "" |
|||
local labelRow = body:tag("tr") |
|||
config.showRefs = not(userRefs=='off' or userRefs=='no') |
|||
labelRow:tag("th")--empty corner cell |
|||
local state = args["state"] or "expanded" |
|||
:css("width", "45pt") |
|||
for colIndex=0, 15 do |
|||
local subset = args["subset"] |
|||
labelRow:tag("th"):wikitext(string.format("%X", colIndex)) |
|||
local subsetRangeTxt = '' |
|||
:css("width", "20pt") |
|||
if subset then |
|||
subsetRangeTxt = mSubsets[subset:lower():gsub('%s+', '_')] |
|||
if(not subsetRangeTxt) then err.format(err.badSubset, subset) end |
|||
end |
|||
local blockName = args["block_name"] or args["block"] or args["name"] or args[1] |
|||
local blockNameLink = args["link_block"] or args["link_name"] |
|||
local blockNameDisplay = args["display_block"] or args["display_name"] or subset or blockName |
|||
local defaultRange = getDefaultRange(blockName) |
|||
local actualBlock = (defaultRange ~= nil) |
|||
local ranges = parseRanges(subsetRangeTxt..','..(args["ranges"] or args["range"] or '')) |
|||
if actualBlock then |
|||
config.pdf = string.format('https://www.unicode.org/charts/PDF/U%04X.pdf', defaultRange.first) |
|||
if #ranges == 0 then ranges = { defaultRange } end |
|||
blockNameLink = blockNameLink or blockName.." (Unicode block)" |
|||
else |
|||
if #ranges == 0 then err.format(err.noRange, {}) end |
|||
end |
end |
||
--real body of table |
|||
local charMask,rowMask = getMask(ranges) |
|||
local rowStart = fromHex(rangeStart.hex:sub(1, -2))--subtract last char from string |
|||
local tableBody = {} |
|||
local rowEnd = fromHex(rangeEnd.hex:sub(1, -2)) |
|||
for i=1,#rowMask do |
|||
for rowIndex=rowStart, rowEnd do |
|||
local rowHex = string.format("%03X", rowIndex) |
|||
local trClass='' |
|||
local row = body:tag("tr") |
|||
if(i > 1 and rowStart ~= (rowMask[i-1]+16)) then |
|||
row:tag("th"):wikitext("U+".. rowHex .. "<i>x</i>") |
|||
trClass = ' class="skip"' |
|||
:attr("rowspan", "2") |
|||
refGrammar.skip.count = refGrammar.skip.count + 1 |
|||
for colIndex=0, 15 do |
|||
local cell = row:tag("td") |
|||
--rowHex .. string.format("%X", colIndex) |
|||
createCell(cell, |
|||
newCodepoint(rowIndex*16 + colIndex), |
|||
args |
|||
) |
|||
end |
end |
||
local |
local subrow = body:tag("tr") |
||
for colIndex=0, 15 do |
|||
local rowOpen, rowClose = string.format('<tr%s>', trClass), '</tr>' |
|||
subrow:tag("td"):addClass("codepoint") |
|||
local rowHeader = string.format('<th class="row">U+%03Xx</th>', rowStart/16) |
|||
:wikitext(string.format("%04X", rowIndex*16 + colIndex)) |
|||
for c = 0,15 do |
|||
table.insert(dataRow, makeGridCell(rowStart+c, charMask)) |
|||
end |
end |
||
local rowHtml = {rowOpen, rowHeader, table.concat(dataRow), rowClose} |
|||
table.insert(tableBody, table.concat(rowHtml)) |
|||
end |
end |
||
end |
|||
local tableOpenFmt = '<table class="wikitable nounderlines unicode-chart collapsible %s">' |
|||
local tableOpen, tableClose = string.format(tableOpenFmt, state), '</table>' |
|||
--------------------- |
|||
local allRefs = table.concat({ makeVersionRef(), makeAutoRefs(), sanitizeUserRefs(userRefs) }) |
|||
-- Header at top of table |
|||
if blockNameLink then |
|||
--------------------- |
|||
blockNameLink = string.format("[[%s|%s]]", blockNameLink, blockNameDisplay) |
|||
local function createTableHeader(head, name, id) |
|||
else |
|||
local page = mRedirect.luaMain(name .. " (Unicode block)", false) |
|||
blockNameLink = blockNameDisplay |
|||
head:tag("th") |
|||
:addClass("header") |
|||
:attr("colspan", "100%") |
|||
:wikitext( |
|||
"<b>[[" .. page .. "|" .. name .. "]]</b>" |
|||
.. "<br />" .. string.format(pdfLink, id) |
|||
.. expandTemplate('ref label', {id .. '_as_of_Unicode_version', 1}) |
|||
) |
|||
end |
|||
--------------------- |
|||
-- Footer at bottom of table |
|||
--------------------- |
|||
local function createTableFooter(foot, id, note) |
|||
local th = foot:tag("th") |
|||
:addClass("footer") |
|||
:attr("colspan", "100%") |
|||
:wikitext("<b>Notes</b>") |
|||
local list = th:tag("ol") |
|||
list:tag("li"):wikitext( |
|||
expandTemplate('note', {id .. '_as_of_Unicode_version'}), |
|||
expandTemplate( |
|||
'Unicode version', |
|||
{prefix= 'Asof', version= mVersion} |
|||
) |
|||
) |
|||
--Notes about categories of cells |
|||
for key, value in pairs(cellType) do |
|||
if value.flag then |
|||
list:tag("li"):wikitext(value.note) |
|||
end |
|||
end |
end |
||
--Manual note |
|||
local titleBar = string.format('<div class="title">%s%s</div>', blockNameLink, allRefs) |
|||
if note then |
|||
local fmtpdf = '<div class="pdf-link">[%s Official Unicode Consortium code chart] (PDF)</div>' |
|||
list:tag("li"):wikitext(note) |
|||
if config.pdf then |
|||
titleBar = titleBar..string.format(fmtpdf, config.pdf) |
|||
end |
end |
||
end |
|||
local titleBarRow = '<tr><th class="title-bar" colspan="17">'..titleBar..'</th></tr>' |
|||
--------------------- |
|||
local columnHeaders = { '<tr>', '<th class="empty"></th>' } |
|||
-- Creates table |
|||
for c = 0,15,1 do table.insert(columnHeaders, string.format('<th class="column">%X</th>', c)) end |
|||
--------------------- |
|||
table.insert(columnHeaders, '</tr>') |
|||
local function createTable(rangeStart, rangeEnd, args) |
|||
local id = 'U' .. rangeStart.hex |
|||
cellType.reserved.flag = false |
|||
cellType.noncharacter.flag = false |
|||
local |
local tbl = mw.html.create("table") |
||
:addClass("wikitable") |
|||
if(config.infoMode) then infoFooter = table.concat(infoTable) end |
|||
:addClass("unicode-block") |
|||
local notesFooter = '' |
|||
if args['blockname'] then |
|||
if config.showRefs and string.len(allRefs) > 0 then |
|||
createTableHeader(tbl, args['blockname'], id) |
|||
notesFooter = '<tr><td class="notes" colspan="17">'.."'''Notes:'''{{reflist}}"..'</td></tr>' |
|||
end |
end |
||
createTableBody(tbl, rangeStart, rangeEnd, args) |
|||
createTableFooter(tbl, id, args['note']) |
|||
return tostring(tbl) |
|||
end |
|||
--------------------- |
|||
local tStyles = frame:extensionTag{ name = 'templatestyles', args = { src = 'Unicode chart/styles.css'} } |
|||
-- Main |
|||
local cStyles = '' |
|||
--------------------- |
|||
if config.useFontCss then |
|||
function p.main(frameArg) |
|||
cStyles = frame:extensionTag{ name = 'templatestyles', args = { src = 'Unicode chart/script styles.css'} } |
|||
frame = frameArg |
|||
local args = getArgs(frame) |
|||
for _, argName in ipairs({'abbr_sub', 'link_sub', 'suffix'}) do |
|||
if args[argName] then |
|||
args[argName] = splitColonList(args[argName]) |
|||
end |
|||
end |
|||
-- look up block by na,e |
|||
if args['blockname'] then |
|||
local range = mUnicode.get_block_info(args['blockname']) |
|||
if range == nil then |
|||
return "invalid blockname" |
|||
end |
|||
return createTable( |
|||
newCodepoint(range[1]), |
|||
newCodepoint(range[2]), |
|||
args |
|||
) |
|||
-- block given as start and end of range |
|||
elseif args['rangestart'] and args['rangeend'] then |
|||
return createTable( |
|||
newCodepoint(args['rangestart']), |
|||
newCodepoint(args['rangeend']), |
|||
args |
|||
) |
|||
end |
end |
||
local html = table.concat({ |
|||
tStyles, cStyles, tableOpen, titleBarRow, |
|||
table.concat(columnHeaders), table.concat(tableBody), |
|||
infoFooter, notesFooter, tableClose |
|||
}) |
|||
return frame:preprocess(html) |
|||
end |
end |
||
return p |
return p |