Documentation icon Τεκμηρίωση module[δημιουργία]
-- Counts wiki links within a wiki article. Supports returning total number of links, blue, red, or a list of red, blue, total, along with blue to red percentage
-- Gts-tg@el wiki, Sep. 2017

local p = {}

-- turn line to list
-- params: line (string), delimiter (string)
-- return list 
local function explode(line, delimiter, specialCharacters)
	local links = {}
	local chars = {
		[":"]=true,
		["."]=true,
		["«"]=true,
		["{"]=true,
		["<"]=true,
		["#"]=true
	}
	local ignore = false
	local regex = '[^' .. delimiter .. ']+'
	
	for link in string.gmatch(line, regex) do -- get all content within [ ]
		
		for schar,value in pairs(chars) do -- clean up non links
		   
		    if (schar == specialCharacters) == false and --  need to regex for multiple characters
		       string.match(link, "%" .. schar) ~= nil
		    then
		    	ignore = true
		    	break
		    end
		    
		end
		
		if ignore == false then
		   link = mw.ustring.gsub(link, '[%[%]]', '') -- remove [[ ]], will be added later if requested
	       links[#links+1] = link
	    end
	end
	
	return links
end

-- merge lists
-- params: l1 (list), l2 (list)
-- return list 
local function listJoin(l1, l2)
    for i=1,#l2 do
        l1[#l1+1] = l2[i]
    end
    return l1
end

-- get wikilinks from text
-- params: text (string)
-- return list 
local function getLinks(text, specialCharacters)
   local links = ''
   local result = {}
   local cleaned = nil
   
   for line in string.gmatch(text,'[^\r\n]+') do
   	   
   	   links = string.match(line, "%[%[.*%]%]") -- cleanup line from anything not in [[ ]]
   	   
   	   if links ~= nil then
   	     links = mw.ustring.gsub(links, '%]%].-%[%[', ']]~[[') -- remove non link text, ~ is used as delimiter for lines where more than one link exists
	     links = mw.ustring.gsub(links, '%|.-%]%]', ']]')      -- remove custom title i.e. [[title|custom title]]
	    
	     result = listJoin(result, explode(links, '~', specialCharacters))

	   end
   end
   
   return result
end

-- count links
-- params: articleTitle (string), linkType (string), showLinks (int)
-- return string 
local function counter(articleTitle, linkType, showLinks, specialCharacters)
	 if articleTitle == '' then return -1 end 
	 local article = mw.title.new(articleTitle)
     local content = article:getContent()
     
     if content == nil then return -1 end 
     local links = getLinks(content, specialCharacters)
	 local str = ''
     
     if linkType ~= 'total' or showLinks == 1 then 
     	
	     local blue = 0

	     for i=1, #links do
		     	-- using mw.wikibase.getEntityIdForTitle(links[i]) (wikidata entry existing) first as it's much faster and saves a few hundred calls
		     	-- using getContent as a fallback to see if article exists, do not use id or exists method as they query the DB and are counted as ''expensive'' and fail after a few hundreds
		     	if mw.wikibase.getEntityIdForTitle(links[i]) or 
		           mw.title.new(links[i],0):getContent() then
		           blue = blue + 1
		           
		           if linkType == 'red' then
		        	links[i] = ''
	               end
	            else
	               if linkType == 'blue' then
		        	links[i] = ''
	               end	
		        end
	     end
	     
	     local red = #links - blue
	     
	     if linkType == 'red' then 
	     	str = red
	     elseif	linkType == 'blue' then 
	     	str = blue
	     elseif linkType == 'percentage' then
	     	str = tostring(math.floor((#links-red)/#links * 100))
	     end
	     
	     if showLinks == 1 then
	     	str = 'Σύνολο: ' .. #links .. ', Μπλέ: ' .. blue .. ', Κόκκινοι: ' .. tostring(red) .. '\n' .. '*[[' .. table.concat(links,']]\n*[[') .. ']]'
	     	str = string.gsub(str, '%*%[%[%]%]\n', '')
	     end
	     
     else
         str = #links
     end
     
    return str
end

-- main
-- params: frame (object)
-- return string 
function p.count(frame)
   local result       = ''
   local articleTitle      = frame.args['article'] or ''
   local linkType          = frame.args['type']
   local showLinks         = tonumber(frame.args['showlinks']) or 0
   local specialCharacters = frame.args['characters'] or nil
   
   -- i18n
   local linkTypes = {
   	   ['κόκκινοι'] = 'red',
   	   ['μπλε']     = 'blue',
   	   ['σύνολο']   = 'total',
   	   ['ποσοστό']  = 'percentage',
   }
   
   linkType = linkTypes[linkType]
   if linkType == nil then showLinks = 1 end
   
   result = counter(articleTitle, linkType, showLinks, specialCharacters)
   if result == -1 then result = 'Δεν βρέθηκε σελίδα με τίτλο ' .. articleTitle end
   	
   return result	
end

return p
-- =p.count{args={['article'] = ''}}