Pergi ke kandungan

Modul:etymon/tree

Daripada Wikikamus
local export = {}

local html_create = mw.html.create
local max = math.max

function export.render(dataTree, config, keywords, make_link_func)
	local function render_recursive(nodeData, isToplevelNode, isUncertain, label, isGroupChild)
		local treeWidth, treeHeight = 0, 0
		local subtrees = {}
		local isGroup = false

		if nodeData.children and #nodeData.children > 0 then
			local firstChild = nodeData.children[1]
			if firstChild and keywords[firstChild.derType] and keywords[firstChild.derType].is_group then
				isGroup = true
			end
		end

		for _, child in ipairs(nodeData.children or {}) do
			if not (child.derType == "root") then
				local subtree, subHeight, subWidth = render_recursive(child, false, child.is_uncertain, child.derType,
					isGroup)
				table.insert(subtrees, subtree)
				treeHeight = max(treeHeight, subHeight)
				treeWidth = treeWidth + subWidth
			end
		end

		local linkParams = { lang = nodeData.lang }
		if isToplevelNode then
			linkParams.alt = "'''" .. (nodeData.alt or nodeData.title) .. "'''"
		else
			linkParams.term = nodeData.title
			linkParams.id = nodeData.id
			linkParams.tr = nodeData.tr
			linkParams.ts = nodeData.ts
			linkParams.alt = nodeData.alt
		end

		local linkContent = html_create()
		linkContent
			:tag('span')
			:addClass('etyl')
			:wikitext(nodeData.lang:getCanonicalName())
			:done()
			:wikitext(' ')
			:tag('span')
			:css('display', 'inline-block')
			:wikitext(make_link_func(linkParams))
			:done()

		local termBlock = html_create('div'):addClass("etytree-block"):node(linkContent)

		local keywordInfo = keywords[label]
		if (label and keywordInfo and keywordInfo.abbrev and not isGroupChild) or isUncertain then
			local labelSpan = termBlock:tag('span'):css({
				['z-index'] = '1',
				position = 'absolute',
				transform = 'translate(-50%)',
				top = 'calc(100% + 5px)',
				left = '50%',
				['border-radius'] = '2px',
				background = config.colors.CYAN,
				['font-size'] = '12px',
				height = '10px',
				['line-height'] = '10px'
			})

			if label and keywordInfo and keywordInfo.abbrev and not isGroupChild then
				local glossary_title = keywordInfo.glossary and keywordInfo.glossary:gsub("_", " ") or keywordInfo
					.abbrev
				local abbr = html_create('abbr'):attr('title', glossary_title):css({
					color = config.colors.BLACK,
					['font-style'] = 'italic',
					['text-decoration'] = 'none'
				}):wikitext(keywordInfo.abbrev)

				if keywordInfo.glossary then
					labelSpan:wikitext('[[Lampiran:Glosari#' .. keywordInfo.glossary .. '|'):node(abbr):wikitext(']]')
				else
					labelSpan:node(abbr)
				end

				if isUncertain then
					labelSpan:tag('abbr'):attr('title', 'uncertain'):css({
						position = 'absolute',
						top = '50%',
						transform = 'translate(0,-48%)',
						left = 'calc(100% + 2px)',
						['font-size'] = '10px',
						['border-radius'] = '2px',
						background = config.colors.PINK,
						padding = '1px 2px',
						['font-weight'] = 'bold',
						['text-decoration'] = 'none'
					}):wikitext('?')
				end
			elseif isUncertain then
				labelSpan:css('background', 'transparent'):tag('abbr'):attr('title', 'uncertain'):css({
					position = 'absolute',
					top = '50%',
					left = '50%',
					transform = 'translate(calc(-50% - 1px),-50%)',
					['font-size'] = '10px',
					['border-radius'] = '2px',
					background = config.colors.PINK,
					padding = '1px 2px',
					['font-weight'] = 'bold',
					['text-decoration'] = 'none'
				}):wikitext('?')
			end
		end

		local currentTree = html_create()
		if #subtrees == 1 then
			currentTree:node(subtrees[1]):tag('span'):css({
				position = 'relative',
				height = '20px',
				['border-right'] = '2px solid ' .. config.colors.GREY
			}):done():node(termBlock)
		elseif #subtrees >= 2 then
			local subtreeContainer = html_create('div'):css({
				position = 'relative',
				display = 'flex',
				['column-gap'] = '0.5em',
				['align-items'] = 'end'
			})

			for i, v in ipairs(subtrees) do
				local column = html_create('div'):css({
					display = 'flex',
					['flex-direction'] = 'column',
					['align-items'] = 'center'
				}):node(v)

				if i == 1 then
					column:tag('span'):css({
						['align-self'] = 'start',
						left = '50%',
						width = 'calc(50% + 0.25em)',
						height = '10px',
						position = 'relative',
						['border-bottom'] = '2px solid ' .. config.colors.GREY,
						['border-left'] = '2px solid ' .. config.colors.GREY,
						['border-bottom-left-radius'] = '4px'
					})
				elseif i == #subtrees then
					column:tag('span'):css({
						['align-self'] = 'end',
						right = '50%',
						width = 'calc(50% + 0.25em)',
						height = '10px',
						position = 'relative',
						['border-bottom'] = '2px solid ' .. config.colors.GREY,
						['border-right'] = '2px solid ' .. config.colors.GREY,
						['border-bottom-right-radius'] = '4px'
					})
				else
					column:tag('span'):css({
						position = 'relative',
						height = '10px',
						['border-right'] = '2px solid ' .. config.colors.GREY
					})
					column:tag('span'):css({
						position = 'relative',
						width = 'calc(100% + 0.5em)',
						['border-bottom'] = '2px solid ' .. config.colors.GREY
					})
				end
				subtreeContainer:node(column)
			end

			local connectingLine = html_create('span'):css({
				position = 'relative',
				height = '20px',
				['border-right'] = '2px solid ' .. config.colors.GREY
			})

			if isGroup and nodeData.children and #nodeData.children > 0 then
				local firstChild = nodeData.children[1]
				local groupKeywordInfo = keywords[firstChild.derType]
				if groupKeywordInfo and groupKeywordInfo.abbrev then
					connectingLine:tag('span'):css({
						position = 'absolute',
						left = '50%',
						top = '50%',
						transform = 'translate(-50%, -50%)',
						background = config.colors.CYAN,
						['font-size'] = '12px',
						['border-radius'] = '2px',
						['z-index'] = '2',
						height = '10px',
						['line-height'] = '10px'
					}):tag('abbr'):attr('title',
						groupKeywordInfo.glossary and groupKeywordInfo.glossary:gsub("_", " ") or groupKeywordInfo
						.abbrev):css({
						color = config.colors.BLACK,
						['font-style'] = 'italic',
						['text-decoration'] = 'none'
					}):wikitext(groupKeywordInfo.abbrev)
				end
			end

			currentTree:node(subtreeContainer):node(connectingLine):node(termBlock)
		else
			currentTree:node(termBlock)
			treeWidth = treeWidth + 1
		end
		return currentTree, treeHeight + 1, treeWidth
	end

	local finalTree, finalHeight, finalWidth = render_recursive(dataTree, true)
	local container = html_create('div'):addClass('etytree-body'):node(finalTree)

	return tostring(html_create('div'):addClass('etytree NavFrame')
		:attr('data-etytree-height', finalHeight)
		:attr('data-etytree-width', finalWidth)
		:tag('div'):addClass('NavHead')
		:css('background', 'var(--wikt-palette-lightergrey)')
		:tag('div'):css('width', '25em'):wikitext('Pokok etimologi'):done()
		:done()
		:tag('div'):addClass('NavContent')
		:css('overflow', 'auto')
		:node(container)
		:done())
end

return export