<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>http://the-metatron.com/index.php?action=history&amp;feed=atom&amp;title=Module%3ADPLlua</id>
	<title>Module:DPLlua - Revision history</title>
	<link rel="self" type="application/atom+xml" href="http://the-metatron.com/index.php?action=history&amp;feed=atom&amp;title=Module%3ADPLlua"/>
	<link rel="alternate" type="text/html" href="http://the-metatron.com/index.php?title=Module:DPLlua&amp;action=history"/>
	<updated>2026-10-24T14:13:05Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.40.1</generator>
	<entry>
		<id>http://the-metatron.com/index.php?title=Module:DPLlua&amp;diff=492&amp;oldid=prev</id>
		<title>ZexisStryfe: Created page with &quot;-- &lt;nowiki&gt; local dpl = {}  dpl.pipe = '¦' local dataContentMarker = '`#@@#`' local usesInclude = {}  -- Custom function for splitting a string because mw.text.split() is waa...&quot;</title>
		<link rel="alternate" type="text/html" href="http://the-metatron.com/index.php?title=Module:DPLlua&amp;diff=492&amp;oldid=prev"/>
		<updated>2020-10-16T16:24:11Z</updated>

		<summary type="html">&lt;p&gt;Created page with &amp;quot;-- &amp;lt;nowiki&amp;gt; local dpl = {}  dpl.pipe = &amp;#039;¦&amp;#039; local dataContentMarker = &amp;#039;`#@@#`&amp;#039; local usesInclude = {}  -- Custom function for splitting a string because mw.text.split() is waa...&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;-- &amp;lt;nowiki&amp;gt;&lt;br /&gt;
local dpl = {}&lt;br /&gt;
&lt;br /&gt;
dpl.pipe = '¦'&lt;br /&gt;
local dataContentMarker = '`#@@#`'&lt;br /&gt;
local usesInclude = {}&lt;br /&gt;
&lt;br /&gt;
-- Custom function for splitting a string because mw.text.split() is waaay too slow&lt;br /&gt;
local function split( str, pattern, plain )&lt;br /&gt;
	local res = {}&lt;br /&gt;
	continue = true&lt;br /&gt;
	local startIndex = 1&lt;br /&gt;
&lt;br /&gt;
	while continue do&lt;br /&gt;
		local i, j = string.find( str, pattern, startIndex, plain )&lt;br /&gt;
		if i then&lt;br /&gt;
			table.insert( res, string.sub( str, startIndex, i-1 ) )&lt;br /&gt;
			startIndex = j + 1&lt;br /&gt;
		else&lt;br /&gt;
			table.insert( res, string.sub( str, startIndex ) )&lt;br /&gt;
			continue = false&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return res&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Also custom function for speed&lt;br /&gt;
local function trim( str )&lt;br /&gt;
	return string.match( str, '^%s*(.-)%s*$' )&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local escapeChars = {&lt;br /&gt;
	['{'] = '&amp;amp;#123;',&lt;br /&gt;
	['\180'] = '&amp;amp;#123;', -- Wtf dpl...&lt;br /&gt;
	['}'] = '&amp;amp;#125;',&lt;br /&gt;
	['\181'] = '&amp;amp;#125;',&lt;br /&gt;
	['['] = '&amp;amp;#91;',&lt;br /&gt;
	[']'] = '&amp;amp;#93;',&lt;br /&gt;
	['|'] = '&amp;amp;#124;',&lt;br /&gt;
	['-'] = '&amp;amp;#8208;',&lt;br /&gt;
	['\226'] = '',&lt;br /&gt;
	['\157'] = '',&lt;br /&gt;
}&lt;br /&gt;
local function escape( str )&lt;br /&gt;
	-- the \226\157\180\181 are used to match ❴ (U+E29DB4) and ❵ (U+E29DB5) wich are 3 bytes long so&lt;br /&gt;
	-- we can't use them directly inside [] patterns. Ustring would fix this but it's way too slow.&lt;br /&gt;
	str = string.gsub( str, '[{}%[%]|%-\226\157\180\181]', escapeChars )&lt;br /&gt;
	return str&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local unEscapeChars = {&lt;br /&gt;
	['&amp;amp;#123;'] = '{',&lt;br /&gt;
	['&amp;amp;#125;'] = '}',&lt;br /&gt;
	['&amp;amp;#91;'] = '[',&lt;br /&gt;
	['&amp;amp;#93;'] = ']',&lt;br /&gt;
	['&amp;amp;#124;'] = '|',&lt;br /&gt;
	['&amp;amp;#8208;'] = '-'&lt;br /&gt;
}&lt;br /&gt;
local function unEscape( str )&lt;br /&gt;
	str = string.gsub( str, '&amp;amp;#%d+;', unEscapeChars )&lt;br /&gt;
	return str&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function removeFormattingSettings( query )&lt;br /&gt;
	local toRemove = {&lt;br /&gt;
		'mode',&lt;br /&gt;
		'table',&lt;br /&gt;
		'tablerow',&lt;br /&gt;
		'tablesortcol',&lt;br /&gt;
		'headingmode',&lt;br /&gt;
		'headingcount',&lt;br /&gt;
		'listattr',&lt;br /&gt;
		'itemattr',&lt;br /&gt;
		'hlistattr',&lt;br /&gt;
		'hitemattr',&lt;br /&gt;
		'userdateformat',&lt;br /&gt;
		'shownamespace',&lt;br /&gt;
		'escapelinks',&lt;br /&gt;
		'titlemaxlength',&lt;br /&gt;
		'replaceintitle',&lt;br /&gt;
		'columns',&lt;br /&gt;
		'rows',&lt;br /&gt;
		'rowsize',&lt;br /&gt;
		'rowcolformat',&lt;br /&gt;
		'resultsheader',&lt;br /&gt;
		'resultsfooter',&lt;br /&gt;
		'oneresultheader',&lt;br /&gt;
		'oneresultfooter',&lt;br /&gt;
		'noresultsheader',&lt;br /&gt;
		'suppresserrors',&lt;br /&gt;
		'noresultsfooter',&lt;br /&gt;
		'format'&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	for _, k in ipairs( toRemove ) do&lt;br /&gt;
		query[k] = nil&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function formatInclude( query )&lt;br /&gt;
	query = split( query, ',', true )&lt;br /&gt;
	local count = #query&lt;br /&gt;
&lt;br /&gt;
	for i = 1, #query do&lt;br /&gt;
		if query[i]:match( '%b{}' ) then -- Check if we are including a template&lt;br /&gt;
			local templateName, params = query[i]:match( '{(.-)[¦|}]([^,]*)' )&lt;br /&gt;
			if params:find( '%S' ) then&lt;br /&gt;
				params:gsub( '^:%-', '' )&lt;br /&gt;
				query[i] = string.format( '{%s}%s', templateName, params )&lt;br /&gt;
				for _ in params:gmatch( ':' ) do&lt;br /&gt;
					count = count + 1&lt;br /&gt;
				end&lt;br /&gt;
			else&lt;br /&gt;
				query[i] = string.format( '{%s¦DPLlua helper}', templateName ) -- Use a helper template to get all the parameters of our included template&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return table.concat( query, ',' ), count&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function formatDpl( query )&lt;br /&gt;
	local queries = {}&lt;br /&gt;
	local count = query.count or 500&lt;br /&gt;
	local offset = query.offset or 0&lt;br /&gt;
	local _usesInclude = false&lt;br /&gt;
	query.count = nil&lt;br /&gt;
	query.offset = nil&lt;br /&gt;
&lt;br /&gt;
	-- We use table format when the include parameter is used to make sure we can&lt;br /&gt;
	-- differentiate between the results in case more than one item is included&lt;br /&gt;
	local dplStringInclude =&lt;br /&gt;
[=[&lt;br /&gt;
{{#dpl:&lt;br /&gt;
|noresultsheader = @@&lt;br /&gt;
|count=%s&lt;br /&gt;
|offset=%s&lt;br /&gt;
|%s&lt;br /&gt;
|table=,&lt;br /&gt;
|tablerow=%s&lt;br /&gt;
}}]=]&lt;br /&gt;
&lt;br /&gt;
	-- Table format requires an include statement so we use format instead.&lt;br /&gt;
	-- This is also a lot faster than adding an empty include statement&lt;br /&gt;
	local dplStringNoInclude =&lt;br /&gt;
[=[&lt;br /&gt;
{{#dpl:&lt;br /&gt;
|noresultsheader = @@&lt;br /&gt;
|count=%s&lt;br /&gt;
|offset=%s&lt;br /&gt;
|%s&lt;br /&gt;
|format=,¦-¦[[%%PAGE%%¦]],,&lt;br /&gt;
}}]=]&lt;br /&gt;
&lt;br /&gt;
	-- Auto generate more than one dpl if count &amp;gt; 500&lt;br /&gt;
	-- The results of these are later combined&lt;br /&gt;
	for i = 1, math.ceil( count / 500 ) do&lt;br /&gt;
		local params = {}&lt;br /&gt;
		local includeCount = 0&lt;br /&gt;
&lt;br /&gt;
		for k, v in pairs( query ) do&lt;br /&gt;
			if k == 'include' then&lt;br /&gt;
				v, includeCount = formatInclude( v )&lt;br /&gt;
				_usesInclude =  true&lt;br /&gt;
			end&lt;br /&gt;
			table.insert( params, k .. '=' .. tostring( v ):gsub( '|', '¦' ) )&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		if _usesInclude then&lt;br /&gt;
			table.insert( queries, string.format(&lt;br /&gt;
				dplStringInclude,&lt;br /&gt;
				count &amp;gt; 500 and 500 or count,&lt;br /&gt;
				offset,&lt;br /&gt;
				table.concat( params, '\n|' ),&lt;br /&gt;
				string.rep( dataContentMarker..'%%'..dataContentMarker..',', includeCount )&lt;br /&gt;
			) )&lt;br /&gt;
		else&lt;br /&gt;
			table.insert( queries, string.format(&lt;br /&gt;
				dplStringNoInclude,&lt;br /&gt;
				count &amp;gt; 500 and 500 or count,&lt;br /&gt;
				offset,&lt;br /&gt;
				table.concat( params, '\n|' )&lt;br /&gt;
			) )&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		count = count - 500&lt;br /&gt;
		offset = offset + 500&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	table.insert( usesInclude, _usesInclude )&lt;br /&gt;
&lt;br /&gt;
	return table.concat( queries )&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function toTable( query )&lt;br /&gt;
	local _usesInclude = table.remove( usesInclude, 1 )&lt;br /&gt;
	local res = {}&lt;br /&gt;
	&lt;br /&gt;
	query = query:gsub( '&amp;lt;p&amp;gt;Extension:DynamicPageList .-&amp;lt;/p&amp;gt;', function(item) res.error = item; return '' end)&lt;br /&gt;
	&lt;br /&gt;
	if not query:match( '^@@' ) then -- @@ is used when no result is found&lt;br /&gt;
		if _usesInclude then&lt;br /&gt;
			query = query:gsub( '\127\'&amp;quot;`UNIQ%-%-nowiki%-%x+%-QINU`&amp;quot;\'\127', function(item) return '&amp;lt;nowiki&amp;gt;' .. mw.text.unstripNoWiki( item ) .. '&amp;lt;/nowiki&amp;gt;' end )&lt;br /&gt;
			query = query:gsub( dataContentMarker..'(.-)'..dataContentMarker, escape )&lt;br /&gt;
			query = query:gsub( '{|.-|%-', '') -- Remove the header of the table&lt;br /&gt;
			-- Replace the footer of the table width a row indicator. This effectively&lt;br /&gt;
			-- combines the output of multiple dpl queries when count &amp;gt; 500&lt;br /&gt;
			query = query:gsub( '|}', '|-' )&lt;br /&gt;
		end&lt;br /&gt;
	&lt;br /&gt;
		query = trim( query )&lt;br /&gt;
		query = split( query, '|-', true ) -- Results of the returned pages are separated by |-&lt;br /&gt;
	&lt;br /&gt;
		for _, v in ipairs( query ) do&lt;br /&gt;
			if v:match( '%S' ) then&lt;br /&gt;
				v = trim( v )&lt;br /&gt;
				local title = v:match( '^|%[%[(.-)|' )&lt;br /&gt;
				local dataList = v:match( '^|.-|.-|(.*)' ) -- This is everything after the title&lt;br /&gt;
	&lt;br /&gt;
				if not _usesInclude then&lt;br /&gt;
					if title and title ~= '' then&lt;br /&gt;
						table.insert( res, title )&lt;br /&gt;
					end&lt;br /&gt;
				else&lt;br /&gt;
					-- When multiple includes are used (e.g. include={Template1},{Template2}) its results are separated by a pipe&lt;br /&gt;
					dataList = split( dataList, '|', true )&lt;br /&gt;
					local _dataList = {}&lt;br /&gt;
	&lt;br /&gt;
					for _, dataItem in ipairs( dataList ) do&lt;br /&gt;
						dataItem = unEscape( dataItem )&lt;br /&gt;
						-- When we include an entire template we use the %ARGS% parameter supplied by dpl.&lt;br /&gt;
						-- However all | characters are repaced with §, e.g.:&lt;br /&gt;
						-- §nameLessParam&lt;br /&gt;
						-- §param = text [[wowee§link text]]&lt;br /&gt;
						-- §param2 = text {{something§something else}}&lt;br /&gt;
						dataItem = dataItem:gsub( '%b{}', function(x) return x:gsub( '§', '|' ) end ) -- Restore pipe characters inside links and templates&lt;br /&gt;
						dataItem = dataItem:gsub( '%b[]', function(x) return x:gsub( '§', '|' ) end )&lt;br /&gt;
						dataItem = trim( dataItem )&lt;br /&gt;
	&lt;br /&gt;
						if dataItem:match( '§' ) then -- Check if we included a template&lt;br /&gt;
							dataItem = split( dataItem, '§', true )&lt;br /&gt;
							local _dataItem = {}&lt;br /&gt;
	&lt;br /&gt;
							for i, item in ipairs( dataItem ) do&lt;br /&gt;
								if i ~= 1 then -- skip first item as it is a false empty string created by splitting on § when the string started with a §&lt;br /&gt;
									if item:find( '=' ) then -- Check if the parameter is named or unnamed&lt;br /&gt;
										local param, value = item:match( '^%s*(.-)%s*=%s*(.-)%s*$' )&lt;br /&gt;
										_dataItem[ param ] = value&lt;br /&gt;
									else&lt;br /&gt;
										table.insert( _dataItem, trim( item ) )&lt;br /&gt;
									end&lt;br /&gt;
								end&lt;br /&gt;
							end&lt;br /&gt;
	&lt;br /&gt;
							dataItem = _dataItem&lt;br /&gt;
						end&lt;br /&gt;
	&lt;br /&gt;
						table.insert( _dataList, dataItem )&lt;br /&gt;
					end&lt;br /&gt;
	&lt;br /&gt;
					if title and title ~= '' then&lt;br /&gt;
						table.insert( res, { title=title, include=_dataList } )&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return res&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Accepts a series of tables each containig the settings for a dpl query.&lt;br /&gt;
-- Combinig multiple dpl queries yields better performance than doing them sequentially&lt;br /&gt;
function dpl.ask( ... )&lt;br /&gt;
	local queries = { ... }&lt;br /&gt;
&lt;br /&gt;
	for i = 1, #queries do&lt;br /&gt;
		removeFormattingSettings( queries[i] )&lt;br /&gt;
		queries[i] = formatDpl( queries[i] )&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	queries = table.concat( queries, '$@µ@$' )&lt;br /&gt;
	local time = os.clock()&lt;br /&gt;
	queries = mw.getCurrentFrame():preprocess( queries )&lt;br /&gt;
	time = os.clock() - time&lt;br /&gt;
	queries = split( queries, '$@µ@$', true )&lt;br /&gt;
&lt;br /&gt;
	for i = 1, #queries do&lt;br /&gt;
		queries[i] = toTable( queries[i] )&lt;br /&gt;
		queries[i].time = time&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return unpack( queries )&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return dpl&lt;br /&gt;
-- &amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>ZexisStryfe</name></author>
	</entry>
</feed>