Edge Rewrite
// HTMLRewriter · presentation

This page was redesigned at the edge.

Cloudflare fetched the original article and streamed it through HTMLRewriter to apply an entirely new visual system without rebuilding the source page.

Jump to content

Module:Sandbox/Ahecht/Xviews

From Wikipedia, the free encyclopedia
-- HELPER FUNCTIONS --
local function notblank(v) return (v or '' ) ~= '' end
local function ifblank(v, alt) return notblank(v) and v or alt end
local function red(v) return '<span style="color: red;">' .. v .. '</span>' end
local function getContent(page) return string.gsub(mw.title.new(page).content, '^Date,"[^"]+"', '') end
local function diffDays(dargs)
	return require('Module:diff days')['diff_days'](
		mw.getCurrentFrame():newChild{ title = 'Template:Diff_days', args = dargs }
	)
end
local showTimeLine = require('Module:Horizontal timeline')._showTimeLine
local Text = require('Module:Text').Text()

-- EXPORTED CONSTANTS --
local p = {
	gSTALE = function() return 30 end, --global for representing the age in days after which a pageviews file, and any chart based on it, becomes stale and no longer appropriate for display on a Talk page. Stale pages should have their pageviews file updated.
	gCOUNT = function() return 75 end, --global for representing the default number of days to display in the chart; overridable with param {{para|ct}}.
}

function p._xviews(args)														-- {{xviews}}
	-- args contains stale, days, ct, log, and mode
	local page = ifblank(args[1], mw.title.getCurrentTitle().fullText .. '/pageviews')
	if mw.title.new(page).exists then
		local stale = tonumber(ifblank(args.stale, p.gSTALE()))
		if tonumber(p._age(page)) > stale then --stale:
			return red(mw.ustring.format(
				'The pageviews file [[%s]] is more than %d days old; please see [[Template:Xviews#Instructions|Instructions]].',
				page, stale
			))
		else --not stale:
			return p._xvmain(page, {ct = ifblank(args.days, ifblank(args.ct, p.gCOUNT()))}) ..
				((notblank(args.log) or notblank(args.mode)) and '' or p._xAxis(page, {})) -- p._xAxis() doesn't handle log values or vertical bars yet
		end
	else
		return red('Missing required pageviews file.') ..
			' See [[Template:Xviews#Instructions|Instructions]].'
	end
	
end
function p.xviews(frame)
	return p._xviews(frame.args)
end
	

function p._age(page)															-- {{xviews/age}}
	local nthview = p._nthView(page, p._viewCount(page))
	nthview = Text.split(nthview, ':', true)[1]
	return diffDays({nthview, mw.getContentLanguage():formatDate('j F Y'), precision=0})
end
function p.age(frame)
	return p._age(ifblank(frame.args[1] or 'Talk:Liberation of France/pageviews'))
end

function p._nthView(page, index)												-- {{xviews/nth view}}
	local content = string.gsub(getContent(page), '.?(202%d%-%d%d%-%d%d)%,?(%d+)', '%1:%2,')
	content = string.gsub(content, "^%s*,%s*(.-)%s*,$", "%1")
	local items = {}
    for item in string.gmatch(content, "([^,]+)") do
        table.insert(items, mw.text.trim(item))
    end
	index = tonumber(index)
    if index < 0 then
        index = #items + index + 1
    end
	return items[index]
end
function p.nthView(frame)
	return p._nthView(
		ifblank(frame.args[1] or 'Talk:Liberation of France/pageviews'),
		ifblank(frame.args[2] or 3)
	)
end

function p._viewCount(page)														-- {{xviews/view count}}
	local str = string.gsub(getContent(page), '.?202%d%-%d%d%-%d%d', '')
	str = string.gsub(str, ',', '', 1)
	-- Remove leading and trailing delimiters (along with any surrounding whitespace)
    str = str:gsub("^%s*,%s*", ""):gsub("%s*,%s*$", "")
	-- Normalize internal consecutive delimiters to a single delimiter (replace ",," with ",")
    str = str:gsub("%s*,%s*,%s*", ',')
    return select(2, str:gsub(',', '')) + 1
end
function p.viewCount(frame)
	return p._viewCount(ifblank(frame.args[1], 'Talk:Liberation of France/pageviews'))
end

function p._xvmain(page, xargs)													-- {{xviews/xvmain}}
	-- xargs contains ct, log, mode, and debug
	local output = {}
	local stop = p._viewCount(page)
	local start = stop - math.min(152, ifblank(xargs.ct, 93)) + 1
	local iargs = {
		page = page,
		max = p._maxViews(page),
		log = xargs.log, -- logarithmic scale (not implemented yet)
		mode = xargs.mode, -- bar display orientation  (mode=vert not implemented yet)
		debug = xargs.debug, -- set to non-empty for loop debug output emitted by p._itemBar()
	}
	for n = start, stop do
		iargs.n = n
		table.insert(output, p._itemBar(iargs))
	end
	return table.concat(output)
end
function p.xvmain(frame)
	local xargs = frame.args
	xargs.ct = ifblank(xargs.ct, 93)
	return p._xvmain(ifblank(xargs[1], 'Talk:Liberation of France/pageviews'), xargs)
end

function p._itemBar(iargs)														-- {{xviews/item bar}}
	-- iargs contains n, page, max, log, mode, and debug
	if iargs.debug then
		return mw.ustring.format("page=%s, n=%s, label=%s",
			ifblank(iargs.page, 'missing'),
			ifblank(iargs.n, 'missing'),
			ifblank(iargs.label, 'missing')
		)
	end
	local nthview = p._nthView(iargs.page, ifblank(iargs.n, 1))
	if not nthview then
		error("Error generating item bar for item #" .. ifblank(iargs.n, 1) .. ". Range may be invalid")
	end
	local val = Text.split(nthview, ':', true)[2]
	local width = val * 100 * 0.88 / p._maxViews(iargs.page)
	width = tonumber(string.format("%.2f", width))
	local label = p._xlabel(Text.split(nthview, ':', true)[1], 'y')
	return p._vbar(width, val, {label = label})
end
function p.itemBar(frame)
	local iargs = frame.args
	iargs.page = ifblank(iargs.page, 'Talk:House of the Dragon/pageviews')
	iargs.n = ifblank(iargs.n, 1)
	return p._itemBar(iargs)
end

function p._vbar(width, val, vargs)												-- {{xviews/vbar}}
	-- vargs contains label, label-style, thick, style, val, and val-style
	local ts =  mw.getCurrentFrame():extensionTag{
		name = 'templatestyles',
		args = {src = 'Template:Xviews/vbar/styles.css'}
	}
	local div = mw.html.create('div'):attr('class', 'vbar')
	if notblank(vargs.label) then
		div:tag('span')
			:attr('class', 'vbar-labelh')
			:cssText(ifblank(vargs['label-style']))
			:wikitext(vargs.label)
	end
	div:tag('span')
		:attr('class', 'vbar-h')
		:attr('alt', 'Page views for (date) = (views).')
		:css('height', ifblank(vargs['thick']))
		:css('width', width .. '%')
		:cssText(ifblank(vargs.style))
	if notblank(val) then
		div:tag('span')
			:attr('class', 'vbar-valh')
			:cssText(ifblank(vargs['val-style']))
			:wikitext(val)
	end
	return ts .. tostring(div)
end
function p.vbar(frame)
	local vargs = frame.args
	return p._vbar(ifblank(vargs[1], 75), ifblank(vargs[2], ifblank(vargs.val, 2136)), vargs)
end

function p._xlabel(date, bold01)												-- {{xviews/xlabel}}
	local replace = ((date:sub(-3) == '-01') and notblank(bold01)) and "'''%1'''" or "%1"
	return string.gsub(date, '20[23]%d%-(%d%d%-%d%d)', replace)
end
function p.xlabel(frame)
	return p._xlabel(ifblank(frame.date, '2024-06-01'), frame.bold01)
end

function p._maxViews(page)														-- {{xviews/max views}}
	local views = 0
	local content = string.gsub(getContent(page), '.?202%d%-%d%d%-%d%d', '')
	for v in Text.gsplit(content, ',', true) do
		v = tonumber(v)
		if (v and v > views) then views = v end
	end
	return views
end
function p.maxViews(frame)
	return p._maxViews(ifblank(frame.args[1], 'Talk:Liberation of France/pageviews'))
end

function p._xAxis(page, xargs)													-- {{xviews/x-axis}}
	-- xargs contains shift, caption, ff
	local div = mw.html.create('div')
		:css('margin', '-22px 0 0 ' .. ifblank(xargs.shift, '16px'))
		:wikitext(
			showTimeLine({
				caption = ifblank(xargs.caption, 'page views for ' .. mw.title.new(page).rootText),
				border = 'none',
				from = 0,
				to = p._maxViews(page),
				inc = tonumber(string.format("%.0f", ifblank(xargs.ff, 1.0) * p._maxViews(page)/100)) * 10,
				row1 = 'scale',
				['axis-nudge'] = '-0.8em',
				['axis-0'] = '<span style="padding-left:10px">0</span>'
			})
		)
	return tostring(div)
end
function p.xAxis(frame)
	return p._xArgs(ifblank(frame.args[1], 'Talk:Liberation of France/pageviews'), frame.args)
end

return p