Edge Rewrite
Jump to content

Module:Word count

From Wikipedia, the free encyclopedia

--- This module implements {{tl|Word count}}.
--
-- @module Word_count
-- @alias p
-- @release alpha
-- @require Module:Arguments


local p = {}
local yn = require("Module:Yesno")
local pv = require("Module:If preview")
local pvWarning = pv._warning

--- Strips wikitext
-- @param {string} text Text to strip
-- @return Stripped text
local function stripWikitext(text)
	text = mw.ustring.gsub(text, "<!%-%-.-%-%->", "")
	text = mw.ustring.gsub(text, "<ref[^>/]->.-</ref>", "")
	text = mw.ustring.gsub(text, "<ref[^/>]*/>", "")
	text = mw.ustring.gsub(text, "{{.-}}", "")
	text = mw.ustring.gsub(text, "{|.-|}", "")
	return text
end

--- Gets the page content
-- @param {string} pagename Name of page
-- @return Page content
local function getPageText(pagename)
	if not pagename or pagename == "" then
		return nil
	end

	local title = mw.title.new(pagename)
	if not title or not title.exists then
		return nil
	end

	return title:getContent()
end

--- Main entry point for modules
-- @param {string} str Input string
-- @param {number} limit Word count limit
-- @return table with necessary outputs

function p._main(str, limit)
	local strout = ""
	limit = limit or math.huge
	local count = 0
	local phrases = mw.text.split(str, "%s")
	local separators = {}
	for match in mw.ustring.gmatch(str, "%s") do
		table.insert(separators, match)
	end
	for k,v in pairs(phrases) do
		if (count < limit) then
			strout = strout .. v .. (separators[k] ~= nil and separators[k] or "")
		end
		if v ~= "" then
			count = count + 1
		end
	end
	return {str = str, trimmedstr = strout, count = count}
end

--- Entrypoint for template
-- @param {table} frame processing frame
-- @param {table} frame.args Template arguments
-- @param {string} frame.args.page Page mode
-- @param {string} frame.args.limit Word count limit
-- @param {boolean} frame.args.showcount whether to show the word count
-- @param {boolean} frame.args.trim Whether to trim at the word count limit
-- @param {boolean} frame.args.unsubst Whether to convert substitutions into transclusions
-- @param {string} frame.args.prepend What to prepend prior to word limited section
-- @param {string} frame.args.append What to append after word limited section
-- @return {string} Output wikitext
function p.main(frame)
	local args = require("Module:Arguments").getArgs(frame)
	local str = args[1] or ''
	local pageMode = args.page ~= nil
	if args.page then
		local pageText = getPageText(args.page)
		if not pageText then
			return '<span class="error">Invalid or non-existent page</span>'
		end
		str = stripWikitext(pageText)
	end
	local limit = tonumber(args['limit']) or tonumber(args[2]) or math.huge
	local result = p._main(str, limit)
	mw.logObject(result)
	local out = ''
	if (yn(args['showcount'] or false) and not mw.isSubsting()) or frame:preprocess('{{REVISIONID}}') == "" then -- always show in preview
		if limit == math.huge then
			out = out .. 'Word count: ' .. result['count'] .. '<br/>'
		elseif 0 <= result['count'] and result['count'] < limit / 2 then
			out = out .. 'Word count: <span class="wordcount-good">' .. result['count'] .. '</span>/' .. limit ..  '<br>'
		elseif limit / 2 <= result['count'] and result['count'] < limit then
			out = out .. 'Word count: <span class="wordcount-okay">' .. result['count'] .. '</span>/' .. limit ..  '<br>'
		else
			out = out .. 'Word count: <span class="wordcount-bad">' .. result['count'] .. '</span>/' .. limit .. '<br>'
		end
	end
	if yn(args['trim']) and result['count'] > limit then
		out = out .. pvWarning({"Word count limit of " .. limit .. " exceeded by " .. (result['count'] - limit) .. " words. Additional text will be ignored."})
	end
	local res = (yn(args['trim']) and result['trimmedstr'] or str)
	if not pageMode then
		out = out .. (args['prepend'] or '') .. res .. (args['append'] or '')
	end
	if mw.isSubsting() then
		if args['unsubst'] then
			local f = frame:getParent()
			local title = f:getTitle().text or "#invoke:Word count|main"
			local preout = '{{' .. title .. "\n"
			for k,v in pairs(args) do
				if k == args['unsubst'] or tonumber(k) == tonumber(args['unsubst'] or '0') then
					preout = preout .. '|' .. k .. '=' .. res .. "\n"
				else
					preout = preout .. '|' .. k .. '=' .. v
				end
			end
			return preout .. '}}'
		end
		return out
	end
	return frame:extensionTag("templatestyles", "", {src = "Module:Word_count/styles.css"}) .. out
end

return p