“模块:DPLlua”与“模板:Mbox/styles.css”:页面之间的差异

来自NebulaeWiki
(页面间差异)
(创建页面,内容为“-- <nowiki> local dpl = {} local libraryUtil = require( 'libraryUtil' ) local hasContent = require( 'Module:Paramtest' ).has_content local checkType = libraryUtil.checkType local checkTypeForNamedArg = libraryUtil.checkTypeForNamedArg dpl.pipe = '¦' local dataContentMarker = '`#@@#`' local allIncludedParamNames = {} -- Custom function for splitting a string because mw.text.split() is waaay too slow local function split( str, pattern, plain ) local res = {}…”)
 
(创建页面,内容为“.mbox { position: relative; display: flex; flex-direction: column; margin-top: 0.4rem; margin-bottom: 0.8rem; background-color: var( --color-surface-2 ); border-radius: var( --border-radius--medium ); color: var( --color-base--subtle ); font-size: 0.875rem; } .mbox.mbox-high { background-color: var( --background-color-destructive ); } .mbox.mbox-med { background-color: var( --background-color-warning ); } .mbox-title { display: flex; align-items…”)
 
第1行: 第1行:
-- <nowiki>
.mbox {
local dpl = {}
position: relative;
local libraryUtil = require( 'libraryUtil' )
display: flex;
local hasContent = require( 'Module:Paramtest' ).has_content
flex-direction: column;
local checkType = libraryUtil.checkType
margin-top: 0.4rem;
local checkTypeForNamedArg = libraryUtil.checkTypeForNamedArg
margin-bottom: 0.8rem;
background-color: var( --color-surface-2 );
border-radius: var( --border-radius--medium );
color: var( --color-base--subtle );
font-size: 0.875rem;
}


dpl.pipe = '¦'
.mbox.mbox-high {
local dataContentMarker = '`#@@#`'
background-color: var( --background-color-destructive );
local allIncludedParamNames = {}
}


-- Custom function for splitting a string because mw.text.split() is waaay too slow
.mbox.mbox-med {
local function split( str, pattern, plain )
background-color: var( --background-color-warning );
local res = {}
}
local continue = true
local startIndex = 1


while continue do
.mbox-title {
local i, j = string.find( str, pattern, startIndex, plain )
display: flex;
if i then
align-items: center;
table.insert( res, string.sub( str, startIndex, i-1 ) )
padding: 10px 15px;
startIndex = j + 1
font-weight: 500;
else
}
table.insert( res, string.sub( str, startIndex ) )
continue = false
end
end


return res
.mbox-icon img {
end
width: 14px;
height: auto;
margin-right: 10px;
opacity: 0.5;
}


-- Also custom function for speed
.mbox-text {
local function trim( str )
position: absolute;
return (string.gsub( str, '^%s+', '' ):gsub( '%s+$', '' ))
z-index: 10;
end
padding: 15px 20px;
width: calc(100% - 40px);
background-color: var( --color-surface-2 );
border-radius: var( --border-radius--medium );
box-shadow: var( --box-shadow-dialog );
opacity: 0;
transition: opacity 0.2s ease, box-shadow 0.2s ease;
visibility: hidden;
}


local function mergeItem( tbl, key, item )
.mbox:hover .mbox-text {
if type( tbl[key] ) == 'table' and type( item ) == 'table' then
opacity: 1;
for k in pairs( tbl[key] ) do
visibility: visible;
mergeItem( tbl[key], k, item[k] )
}
end
elseif type( tbl[key] ) == 'table' then
table.insert( tbl[key], item )
else
tbl[key] = { tbl[key], item }
end
end


local escapeChars = {
.mbox-high .mbox-text {
['{'] = '&#123;',
background-color: var( --background-color-destructive );
['}'] = '&#125;',
['['] = '&#91;',
[']'] = '&#93;',
['|'] = '&#124;',
['-'] = '&#8208;'
}
}
local function escape( str )
return (string.gsub( str, '[{}%[%]|%-]', escapeChars ))
end


local unEscapeChars = {
.mbox-med .mbox-text {
['&#123;'] = '{',
background-color: var( --background-color-warning );
['&#125;'] = '}',
['&#91;'] = '[',
['&#93;'] = ']',
['&#124;'] = '|',
['&#8208;'] = '-'
}
}
local function unEscape( str )
return (string.gsub( str, '&#%d+;', unEscapeChars ))
end


local function fixCurlyBrackets( str )
.mbox-需要翻译{
-- the \226\157\180\181 are used to match ❴ (U+2774) and ❵ (U+2775) wich are 3 bytes long (UTF-8) so
    background-color: #ffcc3382;
-- we can't use them directly inside [] patterns. Ustring would fix this but it's way too slow.
    color: rgba(0,0,0,0.8);
return (string.gsub( str, '\226\157[\180\181]', { ['❴'] = '{', ['❵'] = '}' } ))
    border-radius: var(--border-radius--medium);
end
}


local function removeFormattingSettings( query )
/* Dark mode */
local toRemove = {
html.skin-citizen-dark .mbox-icon img {
'mode',
filter: invert( 1 );
'table',
}
'tablerow',
'tablesortcol',
'headingmode',
'headingcount',
'listattr',
'itemattr',
'hlistattr',
'hitemattr',
'userdateformat',
'shownamespace',
'escapelinks',
'titlemaxlength',
'replaceintitle',
'columns',
'rows',
'rowsize',
'rowcolformat',
'resultsheader',
'resultsfooter',
'oneresultheader',
'oneresultfooter',
'noresultsheader',
'suppresserrors',
'noresultsfooter',
'format',
'groupMultiTemplateResults'
}


for _, k in ipairs( toRemove ) do
/* Readability fixes */
query[k] = nil
html.skin-citizen-dark .mbox {
end
color: var( --color-base--emphasized );
end
}
 
local function formatInclude( query )
checkTypeForNamedArg( 'Module:DPLlua.ask', 'include', query, 'string' )
query = split( query, ',', true )
local includedParamNames = {}
local sectionAttributes = {}
 
for i = 1, #query do
if query[i]:match( '%b{}' ) then -- Check if we are including a template
local templateName, extra = query[i]:match( '{(.-)[¦|}](.*)' )
if hasContent( extra ) then
local phantomTemplateName = extra:match( '^(.-)}' ) or extra:match( '^[./].+' )
local phantomTemplatePrefix = extra:match( '^(.-)}' ) and '' or templateName
local params = extra:gsub( '^.-}', '' ):gsub( '^[./].+', '' ):gsub( ':%-', '' )
local sur = hasContent( phantomTemplateName ) and ('¦' .. phantomTemplatePrefix .. phantomTemplateName) or ''
query[i] = string.format( '{%s%s}%s', templateName, sur, params )
 
if hasContent( phantomTemplateName ) then
table.insert( includedParamNames, { name=phantomTemplatePrefix..phantomTemplateName, isTemplate=true, hasPhantomTemplate=true } )
table.insert( sectionAttributes, { hasPhantomTemplate=true } )
else
for param in params:gmatch( ':([^:]*)' ) do
param = trim( param )
table.insert( includedParamNames, { name=templateName, isTemplate=true, param=param } )
end
table.insert( sectionAttributes, { hasPhantomTemplate=false } )
end
else
query[i] = string.format( '{%s¦DPLlua helper}', templateName ) -- Use a helper template to get all the parameters of our included template
table.insert( includedParamNames, { name=templateName, isTemplate=true, includeAll=true } )
table.insert( sectionAttributes, { hasPhantomTemplate=false } )
end
else
table.insert( includedParamNames, { name=trim( query[i] ) } )
table.insert( sectionAttributes, { hasPhantomTemplate=false } )
end
end
 
return table.concat( query, ',' ), includedParamNames, sectionAttributes
end
 
local function formatDpl( query )
local queries = {}
local count = query.count or 500
local offset = query.offset or 0
local usesInclude = false
local includedParamNames = {}
local sectionAttributes
query.count = nil
query.offset = nil
 
-- Use table format so we can place dataContentMarkers around each included parameter. The secseparator
-- is needed to add dataContentMarkers when a phantom template is used
local dplStringInclude =
[=[
{{#dpl:
|noresultsheader=@@
|count=%s
|offset=%s
|%s
|table=,
|listseparators=,\n¦-\n¦[[%%PAGE%%¦]],,
|tablerow=%s
|secseparators=%s
}}]=]
 
-- Table format requires an include statement so we use format instead.
-- This is also a lot faster than adding an empty include statement
local dplStringNoInclude =
[=[
{{#dpl:
|noresultsheader=@@
|count=%s
|offset=%s
|%s
|format=,¦-¦[[%%PAGE%%¦]],,
}}]=]
 
-- Auto generate more than one dpl if count > 500
-- The results of these are later combined
for i = 1, math.ceil( count / 500 ) do
local params = {}
 
for k, v in pairs( query ) do
if k == 'include' then
v, includedParamNames, sectionAttributes = formatInclude( v )
usesInclude =  true
end
 
if type( v ) == 'table' then
for _, x in ipairs( v ) do
table.insert( params, k .. '=' .. tostring( x ):gsub( '|', '¦' ) )
end
else
table.insert( params, k .. '=' .. tostring( v ):gsub( '|', '¦' ) )
end
end
 
if usesInclude then
local secseparators = ''
for _, v in ipairs( sectionAttributes ) do
if v.hasPhantomTemplate then
-- Phantom templates need this because they ignore tablerow formatting
secseparators = secseparators .. '¶¦' .. dataContentMarker .. ',' .. dataContentMarker .. ','
else
secseparators = secseparators .. '¶¦,,'
end
end
 
table.insert( queries, string.format(
dplStringInclude,
count > 500 and 500 or count,
offset,
table.concat( params, '\n|' ),
string.rep( dataContentMarker..'%%'..dataContentMarker..',', #includedParamNames ),
secseparators
) )
else
table.insert( queries, string.format(
dplStringNoInclude,
count > 500 and 500 or count,
offset,
table.concat( params, '\n|' )
) )
end
 
count = count - 500
offset = offset + 500
end
 
table.insert( allIncludedParamNames, includedParamNames )
return table.concat( queries )
end
 
local function toTable( query, groupMultiTemplateResults )
local includedParamNames = table.remove( allIncludedParamNames, 1 )
local usesInclude = #includedParamNames > 0
local res = {}
 
query = query:gsub( '<p>Extension:DynamicPageList .-</p>', function(item) res.error = item; return '' end )
 
if query:find( '^@@' ) then -- @@ is used when no result is found
return res
end
 
if usesInclude then
query = query:gsub( dataContentMarker..'(.-)'..dataContentMarker, escape )
end
 
query = trim( query )
query = split( query, '|-', true ) -- Results of the returned pages are separated by |-
 
for _, v in ipairs( query ) do
if hasContent( v ) and not v:find( '^@@' ) then
v = trim( v )
local title = v:match( '^|%[%[(.-)|' )
local rawDataList = v:match( '^|.-|.-|(.*)' ) -- This is everything after the title
 
if not usesInclude then
if title and title ~= '' then
table.insert( res, title )
end
else
-- When multiple includes are used (e.g. include={Template1},{Template2} or include={Template}:1:2) their results are separated by a pipe
rawDataList = split( rawDataList, '|', true )
local cleanedDataList = {}
 
for _incIndex, dataItem in ipairs( rawDataList ) do
local incIndex = ((_incIndex - 1) % #includedParamNames) + 1 -- Needed in case the same template appears multiple times on the same page
dataItem = unEscape( dataItem )
dataItem = trim( dataItem )
 
if includedParamNames[ incIndex ].isTemplate and includedParamNames[ incIndex ].includeAll then -- Check if we included a full template
-- When we include an entire template we use the %ARGS% parameter supplied by dpl.
-- However all | characters are repaced with §, e.g.:
-- §namelessParam
-- §param = text [[wowee§link text]]
-- §param2 = text {{something§something else}}
dataItem = dataItem:gsub( '\127\'"`UNIQ%-%-nowiki%-%x+%-QINU`"\'\127', function(item) return '<nowiki>' .. item .. '</nowiki>' end )
dataItem = mw.text.unstripNoWiki( dataItem ) -- Unstrip nowiki so we can clean their content
dataItem = fixCurlyBrackets( dataItem ) -- When using the %ARGS% dpl parameter, curly brackets are replaced with ❴ (U+2774) and ❵ (U+2775)
dataItem = dataItem:gsub( '%b{}', function(x) return x:gsub( '§', '|' ) end ) -- Restore pipe characters inside links and templates
dataItem = dataItem:gsub( '%b[]', function(x) return x:gsub( '§', '|' ) end )
dataItem = dataItem:gsub( '<nowiki>(.-)</nowiki>', function(x) return mw.getCurrentFrame():extensionTag( 'nowiki', x ) end ) -- Restrip nowiki
local _dataItem = {}
 
if dataItem ~= '' then
dataItem = split( dataItem:sub( 3 ), '§' ) -- The sub(3) removes the first § at the start. § is 2 bytes wide so start at index 3
 
for i, item in ipairs( dataItem ) do
if item:find( '=' ) then -- Check if the parameter is named or unnamed
local param, value = item:match( '^%s*(.-)%s*=%s*(.-)%s*$' )
_dataItem[ param ] = value
else
table.insert( _dataItem, trim( item ) )
end
end
end
 
dataItem = _dataItem
end
 
local dataListIndex = groupMultiTemplateResults and 1 or math.ceil( _incIndex / #includedParamNames )
if
includedParamNames[ incIndex ].isTemplate and
not includedParamNames[ incIndex ].includeAll and
not includedParamNames[ incIndex ].hasPhantomTemplate
then -- This means there was an include in the form 'include = {template}:param'
local templateName = includedParamNames[ incIndex ].name
local paramName = includedParamNames[ incIndex ].param
paramName = tonumber( paramName ) or paramName -- Keep as string if tonumber fails
cleanedDataList[ dataListIndex ] = cleanedDataList[ dataListIndex ] or {}
cleanedDataList[ dataListIndex ][ templateName ] = cleanedDataList[ dataListIndex ][ templateName ] or {}
if groupMultiTemplateResults and _incIndex > #includedParamNames then
mergeItem( cleanedDataList[ dataListIndex ][ templateName ], paramName, dataItem )
else
cleanedDataList[ dataListIndex ][ templateName ][ paramName ] = dataItem
end
else
local templateName = includedParamNames[ incIndex ].name
cleanedDataList[ dataListIndex ] = cleanedDataList[ dataListIndex ] or {}
if groupMultiTemplateResults and _incIndex > #includedParamNames then
mergeItem( cleanedDataList[ dataListIndex ], templateName, dataItem )
else
cleanedDataList[ dataListIndex ][ templateName ] = dataItem
end
end
end
 
if title and title ~= '' then
for _, v in ipairs( cleanedDataList ) do
table.insert( res, { title=title, include=v } )
end
end
end
end
end
 
return res
end
 
-- Accepts a series of tables each containig the settings for a dpl query.
-- Combinig multiple dpl queries yields better performance than doing them sequentially
function dpl.ask( ... )
local formatTime = os.clock()
local queries = { ... }
local wantsGrouping = {}
 
for i = 1, #queries do
checkType( 'Module:DPLlua.ask', i, queries[i], 'table' )
table.insert( wantsGrouping, queries[i].groupMultiTemplateResults or false )
removeFormattingSettings( queries[i] )
queries[i] = formatDpl( queries[i] )
end
formatTime = os.clock() - formatTime
 
local DPLtime = os.clock()
queries = table.concat( queries, '$@µ@$' )
queries = mw.getCurrentFrame():preprocess( queries )
queries = split( queries, '$@µ@$', true )
DPLtime = os.clock() - DPLtime
 
for i = 1, #queries do
local parseTime = os.clock()
queries[i] = toTable( queries[i], wantsGrouping[i] )
parseTime = os.clock() - parseTime
queries[i]['DPL time'] = DPLtime
queries[i]['Parse time'] = math.floor( (formatTime + parseTime) * 1e5 ) / 1e5 -- os.clock() has a resolution of 10µs
end
 
return unpack( queries )
end
 
-- function dpl.test()
-- local time = os.clock()
 
-- local a, b = dpl.ask({
--    namespace = 'Module',
--    linksto = 'Module:Chart data',
--    distinct = 'strict',
--    ordermethod = 'title',
--    nottitlematch = '%/doc¦%sandbox%¦Exchange/%¦Exchange historical/%¦Chart data',
-- ignorecase = 'true',
-- allowcachedresults = false
-- },{
--    namespace = 'Module',
--    linksto = 'Module:Enum',
--    distinct = 'strict',
--    ordermethod = 'title',
-- nottitlematch = '%/doc¦%sandbox%¦Exchange/%¦Exchange historical/%¦Enum',
--    ignorecase = 'true',
-- allowcachedresults = false
-- })
-- mw.logObject(a)
-- mw.logObject(b)
 
-- local a, b = dpl.ask({
--    namespace = 'Module',
--    linksto = 'Module:Chart data',
--    distinct = 'strict',
--    ordermethod = 'title',
--    nottitlematch = '%/doc¦%sandbox%¦Exchange/%¦Exchange historical/%¦Chart data',
--    ignorecase = 'true',
-- allowcachedresults = false
-- },{
-- namespace = '',
-- ignorecase = 'true',
-- uses = 'Template:Infobox Recipe',
-- count = 50,
-- include = '{Infobox Recipe},{Infobox Item}',
-- allowcachedresults = false
-- })
-- mw.logObject(a)
-- mw.logObject(b)
 
-- local a = dpl.ask{
-- namespace = '',
-- uses = 'Template:Infobox Recipe',
-- include = '{Infobox Recipe}:skill:name,{Infobox Item}:update,{Infobox Item|test}',
-- count = 50,
-- ordermethod = 'title',
-- }
-- mw.logObject(a)
 
-- local q = dpl.ask{
-- uses = "Template:Collections table",
-- category = "Archaeology collections",
-- -- include = "{Infobox collection}:reward,{Collections table}:1:2:3:4:5:6:7:8:9:10:11:12:13:14:15",
-- include = "{Infobox collection}:reward,{Collections table}",
-- count = 100
-- }
-- mw.logObject(q)
-- local q = dpl.ask{
-- namespace = "",
-- uses = "Template:Infobox spell",
-- notcategory = {"Removed content", "Removed spells"},
-- nottitlematch = {"Enchant Crossbow Bolt", "Storm of Armadyl"},
-- include = "{Infobox spell}",
-- }
-- mw.logObject(q)
 
-- local list = dpl.ask{
-- namespace = 'Template',
-- uses = 'Template:Navbox',
-- ordermethod = 'title',
-- include = '{Navbox}:gtitle1:gtitle2',
-- count = 1,
-- offset = 3
-- }
-- mw.logObject(list)
 
-- local list = dpl.ask{
-- namespace = 'User',
-- titlematch = 'CephHunter/Sandbox/test1',
-- include = '{User:CephHunter/Sandbox/test2|User:CephHunter/Sandbox/test3},{User:CephHunter/Sandbox/test3}:1',
-- }
-- mw.logObject(list)
 
-- mw.logObject(dpl.ask{
-- namespace = 'User',
-- ignorecase = 'true',
-- titlematch = 'CephHunter/Sandbox/test1',
-- include = '{User:CephHunter/Sandbox/test2}'
-- })
 
-- mw.logObject(dpl.ask{
-- namespace = 'Module',
-- uses = 'Template:Helper module',
-- titlematch = '%/doc',
-- nottitlematch = 'Exchange/%|Exchange historical/%|Sandbox/%',
-- ordermethod = 'title',
-- include = '{Helper module}, {Helper module}:example',
-- count = 1,
-- offset = 13
-- })
 
-- mw.logObject(dpl.ask{
--        namespace = 'Module',
--        titlematch = 'Chart data|Absorbative calculator',
--        nottitlematch = 'Exchange/%|Exchange historical/%|Sandbox/%|%/doc|DPLlua%',
--        ordermethod = 'title',
--        include = '%0'
-- })
 
-- mw.logObject(dpl.ask{
--        uses = 'Template:Collections table',
--        include = '{Collections table}',
--        count = 5
-- })
 
-- mw.log(os.clock()-time)
-- end
 
return dpl
-- </nowiki>

2023年9月18日 (一) 21:23的版本

.mbox {
	position: relative;
	display: flex;
	flex-direction: column;
	margin-top: 0.4rem;
	margin-bottom: 0.8rem;
	background-color: var( --color-surface-2 );
	border-radius: var( --border-radius--medium );
	color: var( --color-base--subtle );
	font-size: 0.875rem;
}

.mbox.mbox-high {
	background-color: var( --background-color-destructive );
}

.mbox.mbox-med {
	background-color: var( --background-color-warning );
}

.mbox-title {
	display: flex;
	align-items: center;
	padding: 10px 15px;
	font-weight: 500;
}

.mbox-icon img {
	width: 14px;
	height: auto;
	margin-right: 10px;
	opacity: 0.5;
}

.mbox-text {
	position: absolute;
	z-index: 10;
	padding: 15px 20px;
	width: calc(100% - 40px);
	background-color: var( --color-surface-2 );
	border-radius: var( --border-radius--medium );
	box-shadow: var( --box-shadow-dialog );
	opacity: 0;
	transition: opacity 0.2s ease, box-shadow 0.2s ease;
	visibility: hidden;
}

.mbox:hover .mbox-text {
	opacity: 1;
	visibility: visible;
}

.mbox-high .mbox-text {
	background-color: var( --background-color-destructive );
}

.mbox-med .mbox-text {
	background-color: var( --background-color-warning );
}

.mbox-需要翻译{
    background-color: #ffcc3382;
    color: rgba(0,0,0,0.8);
    border-radius: var(--border-radius--medium);
}

/* Dark mode */
html.skin-citizen-dark .mbox-icon img {
	filter: invert( 1 );
}

/* Readability fixes */
html.skin-citizen-dark .mbox {
	color: var( --color-base--emphasized );
}