|
|
| Line 1: |
Line 1: |
| local mArguments = require('Module:Arguments') | | local p = {} |
| local mTableTools = require('Module:TableTools') | | 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 mEntities = require('Module:Unicode chart/entities') | | local mAliases = require('Module:Unicode data/aliases') |
| local mDisplay = require('Module:Unicode chart/display')
| | |
| local mSubsets = require('Module:Unicode chart/subsets') | | local frame |
| local p = {}
| |
| local args = {}
| |
| local config = {
| |
| useFontCss = true,
| |
| showRefs = true,
| |
| infoMode = false,
| |
| }
| |
|
| |
|
| local refGrammar = {
| | ------------------- |
| order = { "white", "combining", "control", "format", "reserved", "nonchar", "skip" },
| | -- General settings |
| white = {
| | ------------------- |
| format = 'White area%s within light green cell%s show%s %s of %sotherwise invisible [[whitespace character]]%s.',
| | local pdfLink = "[https://www.unicode.org/charts/PDF/%s.pdf" |
| singular = { '', '', 's', 'the size', 'an ', '' },
| | .. " Official Unicode Consortium code chart] (PDF)" |
| plural = { 's', 's', '', 'sizes', '', 's' },
| | local cellType = { |
| 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 = { |
| format = 'Gray cell%s indicate%s %sunassigned (reserved) code point%s.', | | note = "Grey areas indicate non-assigned code points", |
| singular = { '', 's', 'an ', '' }, | | flag = false |
| plural = { 's', '', '', 's' },
| | }, |
| count = 0,
| | noncharacter = { |
| },
| | 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)", |
| nonchar = { | | flag = false |
| 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 infoTable = {} | | local hardcodedNumberedAbbrSets = { |
| local err = {
| | -- Block: Variation Selectors |
| format = function(...) return error(string.format(...), 0) end, | | {first = 0xFE00, last = 0xFE0F, str = "VS<br>", startNum = 1}, |
| blockName = 'Unrecognized block name "%s" does not match those defined in [[Module:Unicode data/blocks]]',
| | -- Block: Variation Selectors Supplement |
| refGarbage = 'Refs contain non-ref content: "%s"', | | {first = 0xE0100, last = 0xE01EF, str = "VS<br>", startNum = 17}, |
| badRange = 'Invalid range "%s" specified. Ranges must match [[regular expression]] <code>^[0-9A-F]+(?:[-–][0-9A-F]+)?$</code>', | | -- Block: Sutton SignWriting |
| noRange = 'Please specify a valid block name, range of code points, or named subset', | | -- SIGNWRITING FILL MODIFIER-2 -> SW F# |
| badSubset = 'Invalid subset "%s" specified', | | {first = 0x1DA9B, last = 0x1DA9F, str = 'SW<br>F', startNum = 2}, |
| }
| | -- Block: Sutton SignWriting |
| | -- SIGNWRITING ROTATION MODIFIER-2 -> SW R# |
| | {first = 0x1DAA1, last = 0x1DAAF, str = 'SW<br>R', startNum = 2}, |
| | } |
| | |
| | local specialFormatSets = { |
| | --Unicode block: Tags |
| | --tag for character -> character |
| | {first = 0xE0021, last = 0xE007E, |
| | func = function(codepoint, abbr) |
| | return '&#x'.. string.format("%04X", (codepoint - 0xE0000)) .. ';' |
| | end |
| | }, |
| | } |
|
| |
|
| function debug(...) | | ------------------------- |
| local a = {...}
| | -- pseudo-object oriented |
| if type(a[1]) ~= "string" then mw.log(a[1]) return end | | ------------------------- |
| local _,c = string.gsub(string.gsub(a[1], "%%%%", ""), "%%", "")
| | function newCodepoint(x) |
| for i = 1,math.max(#a, c+1) do
| | if type(x) == "string" then |
| if (type(a[i]) == "nil" or type(a[i]) == "boolean") then a[i] = tostring(a[i]) end | | 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
| | ------------------------- |
| table.last = function(t) if t then return t[#t] else return nil end end
| | -- Sundry small functions |
| | | ------------------------- |
| | | local function expandTemplate(template, argslist) |
| string.formatAll = function(fmt, t)
| | return frame:expandTemplate{ |
| for i=1,#t do t[i] = string.format(fmt, t[i]) end | | title = template, |
| return t | | args = argslist |
| | } |
| 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 makeRange(a,b) | | local function fromHex(hexStr) |
| if(b) then return {first=math.min(a,b),last=math.max(a,b)} else return {first=a,last=a} end | | return tonumber(hexStr, 16) |
| 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 |
|
| |
|
| function parseHex(s) if s then return tonumber(s,16) else return nil end end | | local function splitColonList(strList) |
| function parseRanges(str)
| | local tab = {} |
| local r = {} | | local segments = mw.text.split(strList, '[;\n\t]') |
| str = str:upper():gsub("AND", ",") --avoid parsing A and D as single control chars in row U+000x, whoops | | for _,v in pairs(segments) do |
| for x in mw.ustring.gmatch(str, "[%dA-FUX%+%-]+") do | | local tmp = mw.text.split(v, ':') |
| local a,b = mw.ustring.match(x, "^[UX0%+%-]*([%dA-F]+)[-–][UX0%+%-]*([%dA-F]+)$") | | if tmp[1] and tmp[2] then |
| if(a and b) then
| | tab[fromHex(tmp[1])] = mw.text.trim(tmp[2]) |
| 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 |
| for i = #r,2,-1 do for j = i-1,1,-1 do if rangesMergeable(r[i], r[j]) then
| | return tab |
| 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 |
|
| |
|
| -- Official way to match property values that are strings (including block names):
| | local function getCategory(codepoint) |
| -- Ignore case, whitespace, underscore ('_'), hyphens, and any initial prefix string "is".
| | local category = mUnicode.lookup_control(codepoint.int) |
| -- http://www.unicode.org/reports/tr44/#UAX44-LM3
| | if category ~= "unassigned" then |
| local function propertyValueKey(val)
| | return category |
| return val:lower():gsub('^is', ''):gsub('[-_%s]+', '') | | elseif mUnicode.is_noncharacter(codepoint.int) then |
| | return "noncharacter" |
| | else |
| | return "reserved" |
| | end |
| end | | end |
|
| |
|
| function getDefaultRange(blockName) | | |
| if not blockName then return nil end | | local function getAliasValues(n, key) |
| blockName = propertyValueKey(blockName)
| | local tbl = {} |
| for i,b in ipairs(mBlocks) do
| | if mAliases[n] then |
| if blockName == propertyValueKey(b[3]) then return makeRange(b[1],b[2]) end
| | for i,t in ipairs(mAliases[n]) do |
| | if(not key or t[1] == key) then |
| | table.insert(tbl, t[2]) |
| | end |
| | end |
| end | | end |
| | return tbl |
| end | | end |
|
| |
|
| function getAge(n) | | --------------------- |
| local a = mAge.singles[n] | | -- A single unicode cell within the table |
| if(a) then return a end
| | --------------------- |
| for k,v in pairs(mAge.ranges) do | | local function getCellAbbr(codepoint, category, args) |
| if n >= v[1] and n <= v[2] then return v[3] end | | local function getHardcodedNumberedAbbr(codepoint) |
| | 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
| |
|
| |
|
| function getControlAbbrs(n) return getAliasValues(n, "abbreviation") end
| | --override |
| function getControlAliases(n) return table.concat2(getAliasValues(n, "control"), getAliasValues(n, "figment")) end
| | if (args['abbr_sub'] and args['abbr_sub'][codepoint.int]) then |
| | | return args['abbr_sub'][codepoint.int] |
| function getAliasValues(n, key)
| | end |
| local b,r = mAliases[n], {} | | --exception listed at top |
| if b then for i,t in ipairs(b) do | | local abbr1 = getHardcodedNumberedAbbr(codepoint) |
| if(not key or t[1] == key) then table.insert(r, t[2]) end | | if abbr1 then return abbr1 end |
| end end | | --abbr on list |
| return r | | local abbr2 = getAliasAbbr(codepoint) |
| end
| | if abbr2 then return abbr2 end |
| | | --make own abbr |
| function getAnchorId(n) return string.format("info-%04X", n) end
| | if category == "control" or category == "format" then |
| function getTarget(n)
| | return '<span class="red">' .. abbrFromString(codepoint) .. '</span>' |
| if(config.infoMode) then return "#"..getAnchorId(n) end
| | 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 makeVersionRef() | | local function aliasesStr(codepoint) |
| if(not config.showRefs or mVersion == nil or mVersion == '') then return '' | | local aliasStr = "" |
| else return string.format('<ref name="version">As of [[Unicode#Versions|Unicode version]] %s.</ref>', mw.text.nowiki(mVersion)) end
| | if mAliases[codepoint.int] then |
| end
| | for i,t in ipairs(mAliases[codepoint.int]) do |
| | | 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 table.concat(refs) | | return aliasStr |
| end | | end |
|
| |
|
| --TODO: remove any garbage around/between refs and downgrade this to a warning
| | local function linkChar(unicodeChar, codepoint, args) |
| function sanitizeUserRefs(refTxt) | | if (args['link_sub'] and args['link_sub'][codepoint.int]) then |
| if not config.showRefs then return '' end | | return '[[' .. args['link_sub'][codepoint.int] |
| local trim1 = mw.text.killMarkers(refTxt)
| | .. '|' .. unicodeChar .. ']]' |
| local trim2 = mw.ustring.gsub(trim1, '%s', '') | | elseif args['link'] == "wiki" then |
| if string.len(trim2) > 0 then err.format(err.refGarbage, mw.text.nowiki(trim1))
| | local redir = mRedirect.luaMain(unicodeChar, false) |
| else return refTxt end
| | -- '[[' .. redir .. '|' .. unicodeChar .. ']]' |
| end
| | return expandTemplate('Link if exists', {unicodeChar}) |
| function makeSpan(str, title, repl)
| | elseif args['link'] == "wikt" then |
| local c,t = '','' | | return '[[wikt:' .. unicodeChar .. '|' .. unicodeChar .. ']]' |
| 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 makeAliasList(n) | | local function createCell(cell, codepoint, args) |
| if not mAliases[n] then return '' end | | -- sub functions |
| local t = {} | | local function emptyCell(categoryStr) |
| table.insert(t, '<div class="alias"><ul>')
| | cellType[categoryStr].flag = true |
| for k,v in ipairs(mAliases[n]) do
| | -- flag[categoryStr] = true |
| local tr = string.format('<li class="%s">%s</li>', v[1], v[2])
| |
| table.insert(t, tr)
| |
| end | | end |
| table.insert(t, '</ul></div>') | | local function abbrCell(abbr) |
| return table.concat(t)
| | cell:addClass("abbr-cell") |
| end
| | cell:tag("div"):addClass("abbr-box"):wikitext(abbr) |
| 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 | | |
| end
| | -- main func begins |
| | | local category = getCategory(codepoint) |
| function makeGridCell(n, charMask)
| | cell:addClass(category) |
| local uPlus = string.format("U+%04X", n) | | local abbr = getCellAbbr(codepoint, category, args) |
| local char = mw.ustring.char(n) | | |
| local cfFmt = '<td title="%s" class="char%s"><div>\n%s\n</div></td>' | | if category == "reserved" or category == "noncharacter" then |
| local isControlN, isFormatN = isControl(n), isFormat(n)
| | emptyCell(category) |
| local charName = table.last(getControlAliases(n)) or mUnicode.lookup_name(n) | | elseif abbr then |
| if isControlN then charName = charName or "<control>" end
| | abbrCell(abbr) |
| 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 |
| if sCode then sClass = sClass..string.format(' script-%s', sCode) end | | local unicodeChar = '&#x'.. codepoint.hex .. ';' |
| sClass = sClass..cBox
| | unicodeChar = linkChar(unicodeChar, codepoint, args) or unicodeChar |
| local isCombining = mUnicode.is_combining(n) | | if args['suffix'] and args['suffix'][codepoint.int] then |
| if isCombining then | | unicodeChar = unicodeChar |
| refGrammar.combining.count = refGrammar.combining.count + 1 | | .. '&#x' .. args['suffix'][codepoint.int] .. ';' |
| sClass = sClass.." combining"
| | cell:addClass("modified") |
| display = "◌"..char | |
| end | | end |
| display = makeSpan(display, title, true) | | if args['wrapper'] then |
| local cellFmt = '<td title="%s" class="char%s"%s><div>\n%s\n</div></td>' | | unicodeChar = expandTemplate(args['wrapper'], {unicodeChar}) |
| cell = string.format(cellFmt, title, sClass, sDir, makeLink(linkThis,display))
| | elseif args['font'] then |
| end
| | cell:css("font-family", "'" .. args['font'] .. "'") |
| if(config.infoMode and generateInfoPanel) then
| | --unicodeChar = tostring( |
| local printable = mUnicode.is_printable(n)
| | -- mw.html.create("div") |
| local category = getCategory(n)
| | -- :css("font-family", "'" .. args['font'] .. "'") |
| local info = {
| | -- :wikitext(unicodeChar) |
| n = n, | | --) |
| 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 row = {} | | local name = mUnicode.lookup_name(codepoint.int) |
| for i,x in pairs(r) do table.insert(row, i) end | | name = string.match(name, "<([a-z]+)-%w+>") or name |
| table.sort(row)
| | cell:attr("title", |
| return ch,row | | 'U+' .. codepoint.hex .. |
| | ': ' .. name |
| | .. aliasesStr(codepoint) |
| | ) |
| end | | end |
|
| |
|
| function p.main( frame ) | | --------------------- |
| for k, v in pairs(mArguments.getArgs(frame)) do args[k] = v end | | -- For loops creating the grid of cells |
| config.infoMode = (args["info"] or 'no'):lower() ~= "no" | | --------------------- |
| config.useFontCss = (args["fonts"] or args["font"] or 'yes'):lower() ~= "no" | | local function createTableBody(body, rangeStart, rangeEnd, args) |
| local userRefs = args["refs"] or args["notes"] or args["ref"] or args["note"] or ""
| | --0 through F label row |
| config.showRefs = not(userRefs=='off' or userRefs=='no')
| | local labelRow = body:tag("tr") |
| local state = args["state"] or "expanded" | | labelRow:tag("th")--empty corner cell |
| | | :css("width", "45pt") |
| local subset = args["subset"]
| | for colIndex=0, 15 do |
| local subsetRangeTxt = ''
| | labelRow:tag("th"):wikitext(string.format("%X", colIndex)) |
| if subset then
| | :css("width", "20pt") |
| subsetRangeTxt = mSubsets[subset:lower():gsub('%s+', '_')] | |
| if(not subsetRangeTxt) then err.format(err.badSubset, subset) end
| |
| end | | end |
|
| |
|
| local blockName = args["block_name"] or args["block"] or args["name"] or args[1] | | --real body of table |
| local blockNameLink = args["link_block"] or args["link_name"] | | local rowStart = fromHex(rangeStart.hex:sub(1, -2))--subtract last char from string |
| local blockNameDisplay = args["display_block"] or args["display_name"] or subset or blockName
| | local rowEnd = fromHex(rangeEnd.hex:sub(1, -2)) |
| | | for rowIndex=rowStart, rowEnd do |
| local defaultRange = getDefaultRange(blockName)
| | local rowHex = string.format("%03X", rowIndex) |
| local actualBlock = (defaultRange ~= nil)
| | local row = body:tag("tr") |
| | | row:tag("th"):wikitext("U+".. rowHex .. "<i>x</i>") |
| local ranges = parseRanges(subsetRangeTxt..','..(args["ranges"] or args["range"] or '')) | | :attr("rowspan", "2") |
| | | for colIndex=0, 15 do |
| if actualBlock then | | local cell = row:tag("td") |
| config.pdf = string.format('https://www.unicode.org/charts/PDF/U%04X.pdf', defaultRange.first) | | --rowHex .. string.format("%X", colIndex) |
| if #ranges == 0 then ranges = { defaultRange } end | | createCell(cell, |
| blockNameLink = blockNameLink or blockName.." (Unicode block)" | | newCodepoint(rowIndex*16 + colIndex), |
| else
| | args |
| if #ranges == 0 then err.format(err.noRange, {}) end
| | ) |
| end
| |
| | |
| local charMask,rowMask = getMask(ranges)
| |
| local tableBody = {}
| |
| for i=1,#rowMask do
| |
| local rowStart = rowMask[i]
| |
| local trClass=''
| |
| if(i > 1 and rowStart ~= (rowMask[i-1]+16)) then
| |
| trClass = ' class="skip"'
| |
| refGrammar.skip.count = refGrammar.skip.count + 1 | |
| end | | end |
| local dataRow = {} | | local subrow = body:tag("tr") |
| local rowOpen, rowClose = string.format('<tr%s>', trClass), '</tr>'
| | for colIndex=0, 15 do |
| local rowHeader = string.format('<th class="row">U+%03Xx</th>', rowStart/16)
| | subrow:tag("td"):addClass("codepoint") |
| for c = 0,15 do | | :wikitext(string.format("%04X", rowIndex*16 + colIndex)) |
| 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 |
| local tableOpenFmt = '<table class="wikitable nounderlines unicode-chart collapsible %s">' | | end |
| local tableOpen, tableClose = string.format(tableOpenFmt, state), '</table>'
| | |
| | --------------------- |
| | -- Header at top of table |
| | --------------------- |
| | local function createTableHeader(head, name, id) |
| | local page = mRedirect.luaMain(name .. " (Unicode block)", false) |
| | 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 |
|
| |
|
| local allRefs = table.concat({ makeVersionRef(), makeAutoRefs(), sanitizeUserRefs(userRefs) }) | | --------------------- |
| if blockNameLink then | | -- Footer at bottom of table |
| blockNameLink = string.format("[[%s|%s]]", blockNameLink, blockNameDisplay)
| | --------------------- |
| else
| | local function createTableFooter(foot, id, note) |
| blockNameLink = blockNameDisplay | | 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 |
| local titleBar = string.format('<div class="title">%s%s</div>', blockNameLink, allRefs) | | --Manual note |
| local fmtpdf = '<div class="pdf-link">[%s Official Unicode Consortium code chart] (PDF)</div>'
| | if note then |
| if config.pdf then | | list:tag("li"):wikitext(note) |
| titleBar = titleBar..string.format(fmtpdf, config.pdf) | |
| end | | end |
| local titleBarRow = '<tr><th class="title-bar" colspan="17">'..titleBar..'</th></tr>'
| | end |
|
| |
|
| local columnHeaders = { '<tr>', '<th class="empty"></th>' } | | --------------------- |
| for c = 0,15,1 do table.insert(columnHeaders, string.format('<th class="column">%X</th>', c)) end | | -- Creates table |
| table.insert(columnHeaders, '</tr>') | | --------------------- |
| | local function createTable(rangeStart, rangeEnd, args) |
| | local id = 'U' .. rangeStart.hex |
| | |
| | cellType.reserved.flag = false |
| | cellType.noncharacter.flag = false |
|
| |
|
| local infoFooter = '' | | local tbl = mw.html.create("table") |
| if(config.infoMode) then infoFooter = table.concat(infoTable) end | | :addClass("wikitable") |
| | :addClass("unicode-block") |
| | |
| | if args['blockname'] then |
| | createTableHeader(tbl, args['blockname'], id) |
| | end |
| | createTableBody(tbl, rangeStart, rangeEnd, args) |
| | createTableFooter(tbl, id, args['note']) |
| | |
| | return tostring(tbl) |
| | end |
|
| |
|
| local notesFooter = '' | | --------------------- |
| if config.showRefs and string.len(allRefs) > 0 then | | -- Main |
| notesFooter = '<tr><td class="notes" colspan="17">'.."'''Notes:'''{{reflist}}"..'</td></tr>'
| | --------------------- |
| | function p.main(frameArg) |
| | 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 | | end |
| | | |
| local tStyles = frame:extensionTag{ name = 'templatestyles', args = { src = 'Unicode chart/styles.css'} } | | -- look up block by name |
| local cStyles = ''
| | if args['blockname'] then |
| if config.useFontCss then | | local range = mUnicode.get_block_info(args['blockname']) |
| cStyles = frame:extensionTag{ name = 'templatestyles', args = { src = 'Unicode chart/script styles.css'} } | | 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 |