Permanently protected module
From Wikipedia, the free encyclopedia


require('strict')

local p = {}

local sandbox-- = '/sandbox'

local cfg = mw.loadData('Module:WikiProject banner/config' .. (sandbox or ''))

local args_module = require('Module:Arguments')

local mbox = require('Module:Message box').main

local yesno = require('Module:Yesno')

local frame = mw.getCurrentFrame()

local lang = mw.getLanguage(cfg.language)

local current_title = mw.title.getCurrentTitle()

local parameter_format = function(parameter, value)

	return frame:expandTemplate{title='para', args={parameter, value or ''}}

end



local wikilink = function(link, display)

	if link then

		return display and '[['..link..'|'..display..']]' or '[['..link..']]'

	else

		return display or ''

	end

end



local image = function(image_name, size, alt, position)

	return image_name and '[[File:'

		.. image_name

		.. (size and '|' .. size or '')

		.. (position and '|' .. position or '')

		.. (alt and '|alt=' .. alt or '')

		.. ']]'

end



local if_exists = function(target, fallback) -- function to add wikilink if target exists

	local title = mw.title.new(target)

	if title and title.exists then

		return wikilink(target)

	else

		return fallback or target

	end

end



local isarticle = function(class)

	local article = true

	for _,v in ipairs(cfg.quality.non_article_classes) do

		if class==v then -- class matches one of the non-article classes

			article = false

			break

		end

	end

	return article

end



---------------------------

-- Importance mask --------

---------------------------

local importance_mask = function(raw_importance, class, scale, banner_name)

	local importance

	if scale=='inline' then -- pass importance without change

		importance = raw_importance

	elseif scale=='subpage' then

		local custom_mask = banner_name:subPageTitle('importance')

		if custom_mask.exists and #custom_mask:getContent()>1 then -- pass to custom importance mask

			importance = mw.text.trim(frame:expandTemplate{

				title = custom_mask.prefixedText,

				args = {importance=raw_importance or '¬', class=class}

			})

		end

	else

		importance = frame:expandTemplate{

			title = 'Template:Importance mask',

			args = {raw_importance or '¬', class=class}}

	end

	if importance=='¬' then

		importance = nil

	end

	return importance

end



---------------------------

-- Quality class mask -----

---------------------------

p.readarticleclass = function(options, page) -- used by _main and also Module:Banner shell

	page = page or current_title.prefixedText

	local get_parameter_value = require('Module:Template parameter value').getValue

	local success, result = get_parameter_value(page, cfg.WPBS_redirects, 'class', options)

	return success and result

	-- returns FALSE if banner shell template does not exist on page

	-- returns BLANK if class parameter is not defined or is defined blank

	-- otherwise returns class parameter

end

p.class_mask = function(class, title, FQS, pagetype)

	local resolveFQSgrade = function(class)

		return FQS and lang:ucfirst(class) or 'NA'

	end

	local out = '' -- default to unassessed

	title = title or mw.title.getCurrentTitle()

	local ns = title.namespace

	class = class:match('^%s*(.-)%s*$'):lower()

	if pagetype=='redirect' or pagetype=='soft redirect' then

		out = resolveFQSgrade('redirect')

	elseif ns==1 then -- Talk

		if pagetype=='disambiguation page' or class=='dab' or class=='disambig' or class=='disambiguation' or class=='disamb' then

			out = resolveFQSgrade('disambig')

		elseif class=='start' or class=='stub' then -- Ucfirst

			out = lang:ucfirst(class)

		elseif class=='b' or class=='c' or class=='fa' or class=='fl' or class=='a' or class=='ga' then -- Upper-case

			out = class:upper()

		elseif class=='list' or class=='sia' or class=='si' or class=='sl' then-- List

			out = 'List'

		end

	elseif ns==7 or ns==711 then -- File talk

		if class=='fm' and FQS then

			out = 'FM'

		else

			out = resolveFQSgrade('file')

		end

	elseif ns==15 then -- Category talk

		out = resolveFQSgrade('category')

	elseif ns==101 then -- Portal talk

		out = resolveFQSgrade('portal')

	elseif ns==11 or ns==829 then -- Template talk

		out = resolveFQSgrade('template')

	elseif ns==5 then -- Wikipedia talk

		out = resolveFQSgrade('project')

	elseif ns==119 then -- Draft talk

		out = resolveFQSgrade('draft')

	else

		out = 'NA'

	end

	return out

end



local page_assessment = function(project, class, importance) -- add PageAssessments parser function

	local assessment = table.concat({project, class or '', importance or ''},'|')

	frame:preprocess('{{#assessment:' .. assessment .. '}}')

end



local bubble = function(text, colour, conflict)

	local out = mw.html.create('span')

		:addClass('wpb-header-bubbles')

		:css('background', colour)

		:css('color', '#222' )

		:css('border', conflict and cfg.quality.conflict.border or (cfg.quality.border..' '..colour))

		:wikitext(text)

	return tostring(out)

end



p._main = function(args, raw_args, demo, banner_name)

---------------------------

-- Initialise parameters --

---------------------------

local project = args.PROJECT or 'PROJECT'

local project_name = args.PROJECT_NAME or 'WikiProject ' .. project

local project_link = mw.title.new(args.PROJECT_LINK or 'Wikipedia:' .. project_name)

local pagetype = demo and not args.demo_page and 'article' or require('Module:Pagetype' .. (sandbox or ''))._main({

	page = args.demo_page,

	dab = 'disambiguation page'

})

local rows, nested_ratings, task_forces, notes, categories, taskforce_categories = {}, {}, {}, {}, {}, {}

local add_category = function(category, key)

	if category and category~='none' then

		table.insert(categories, {category = category, key = key})

	end

end

local parse_text = function(text)

	return text and text:gsub('_PAGETYPE_', pagetype)

end

for arg_name, arg_value in pairs(args) do

	local tf_match = mw.ustring.match(arg_name,'^tf (%d+)$')

	local note_match = mw.ustring.match(arg_name,'^note (%d+)$')

	if tf_match and yesno(arg_value, true) then

		table.insert(task_forces, tf_match)

	elseif note_match and yesno(arg_value, true) then

		table.insert(notes, note_match)

	else

		local tf, cat = mw.ustring.match(arg_name,'^tf (%d+) cat (%d+)$')

		if tf and yesno(arg_value, true) then

			if not taskforce_categoriestf then -- initialise table

				taskforce_categoriestf = {}

			end

			table.insert(taskforce_categoriestf], cat)

		end

	end

end

table.sort(task_forces, function (x, y) return tonumber(x) < tonumber(y) end)

table.sort(notes, function (x, y) return tonumber(x) < tonumber(y) end)

local warning = ''

---------------------------

-- Location warning -------

---------------------------

local show_namespace_warning = not (current_title.isTalkPage or demo)

if show_namespace_warning then

	local text = cfg.namespace_warning.text:format(

		pagetype,

		current_title.talkPageTitle.fullText,

		parameter_format('category', 'no')

	)

	local sortkey = current_title.namespace==10 and cfg.namespace_warning.sortkey_on_template_page or cfg.namespace_warning.sortkey

	if current_title.namespace==10 then -- on the Template namespace

		text = text .. '  ' .. cfg.namespace_warning.on_template_page:format(

			parameter_format('BANNER_NAME'),

			current_title.prefixedText

		)

	end

	warning = mbox('ombox', {

		image = '[[File:' .. cfg.namespace_warning.image .. '|40px]]',

		type = cfg.namespace_warning.type_,

		text = text

	})

	if not current_title.subjectPageTitle:inNamespace(2) then

		add_category(cfg.namespace_warning.categories, sortkey)

	end

end

---------------------------

-- Substitution warning ---

---------------------------

if args.substcheck=='SUBST' then

	local text = cfg.subst_warning.text:format(

		project_name,

		'<code>&#123;&#123;'..banner_name.prefixedText..'&#125;&#125;</code>'

	)

	warning = warning .. mbox('ombox', {

		image = '[[File:' .. cfg.subst_warning.image .. '|40px]]',

		type = cfg.subst_warning.type_,

		text = text,

	}) .. cfg.subst_warning.categories

end

---------------------------

-- Primary image/text -----

---------------------------

local assessment_cat = args.ASSESSMENT_CAT or project .. ' articles'

local primary_image = function(image_name, size)

	local cell = mw.html.create('td')

	if image_name and image_name~='' then

		cell:addClass('mbox-image wpb-image')

		:wikitext(image(image_name, size, cfg.image.alt))

	else

		cell:addClass('mbox-empty-cell')

	end

	cell:done()

	return cell

end

local portal = args.PORTAL

local portal_box = portal and frame:expandTemplate{title='Portal', args={portal}} or ''

local main_text = portal_box .. (parse_text(args.MAIN_TEXT) or cfg.main_text:format(

	pagetype,

	project_link.prefixedText,

	project_name,

	args.MAIN_ARTICLE and if_exists(args.MAIN_ARTICLE) or if_exists(project, project .. ' articles'),

	project_link.talkPageTitle.prefixedText

))

local image_left_size = args.IMAGE_LEFT_SIZE or cfg.image.default_size

local primary_row = mw.html.create('tr')

	:node(primary_image(args.IMAGE_LEFT, image_left_size))

	:tag('td')

		:addClass('mbox-text')

		:wikitext(main_text)

		:tag('span')

			:addClass('metadata wpb-metadata')

			:tag('span'):addClass('wpb-project'):wikitext(project):done()

			:tag('span'):addClass('wpb-project_link'):wikitext(project_link.prefixedText):done()

			:tag('span'):addClass('wpb-banner_name'):wikitext(banner_name.prefixedText):done()

			:tag('span'):addClass('wpb-assessment_cat'):wikitext(assessment_cat):done()

		:done()

	:done()	

	:node(primary_image(args.IMAGE_RIGHT, args.IMAGE_RIGHT_SIZE or cfg.image.default_size))

:done()

table.insert(rows, primary_row)

---------------------------

-- Quality assessment -----

---------------------------

local assessment_link = args.ASSESSMENT_LINK

if not assessment_link then

	local fallback = mw.title.new(project_link.prefixedText .. '/Assessment')

	assessment_link = fallback.exists and fallback.prefixedText

elseif assessment_link=='no' then

	assessment_link = nil

end

local check_exists = function(class, assessment_cat) -- check if category exists and is not blank

	if not isarticle(class) then

		local cat =  mw.title.new('Category:' .. class .. '-Class' .. ' ' .. assessment_cat)

		return (cat.exists and #cat:getContent()>0) and class or 'NA' -- automatically use NA for non-article pages if category does not exist

	else

		return class

	end

end

local class = raw_args.class

if class then -- banner gives quality ratings

	local title = args.demo_page and mw.title.new(args.demo_page) or current_title

	local article_class = p.readarticleclass({ignore_subtemplates=true}, title.prefixedText)

	if not article_class then

		if pagetype=='article' then

			add_category('Articles with WikiProject banners but without a banner shell')

		else

			add_category('WikiProject banners without banner shells')

		end

	end

	article_class = article_class and p.class_mask(article_class, title, false, pagetype)

	local show_quality, conflict = true, false

	if args.QUALITY_CRITERIA=='custom' then -- project has opted out of standard assessment scale and uses a custom mask

		local custom_mask = banner_name:subPageTitle('class')

		if custom_mask.exists and #custom_mask:getContent()>1 then

			raw_args.demo_page = args.demo_page -- send demo_page to custom mask

			class = mw.text.trim(frame:expandTemplate{

				title = custom_mask.prefixedText,

				args = raw_args

			})

			if class=='' and article_class and article_class~='' then -- if unassessed and article class exists, check if it can be inherited

				local new_arg_table = {}

				for arg, val in pairs(raw_args) do -- construct new argument table to send to custom mask

					new_arg_tablearg = val

				end

				new_arg_table.class = article_class -- replace class with inherited class

				local article_class_normalised = mw.text.trim(frame:expandTemplate{

					title = custom_mask.prefixedText,

					args = new_arg_table

				})

				if article_class_normalised and article_class_normalised~='' then

					class = article_class_normalised -- inherit class from article_class normalised by custom mask

				else

					article_class = nil -- effectively no article_class for this banner

				end

			end

		end

	else

		class = p.class_mask(class, title, true, pagetype)

	end

	if article_class then -- banner shell exists

		if article_class=='' then -- no article class defined

			if class=='' then -- local class also does not exist, check whether any other class parameters are defined inside the shell

				local classparam = p.readarticleclass({ignore_blank=true, only_subtemplates=true}, title.prefixedText)

				if classparam=='' then -- no class parameters defined, display as globally unassessed

					show_quality = false -- hide quality class in project banner

				end

			else

				add_category('Pages using WikiProject banner shell without a project-independent quality rating')

			end

		elseif class=='' or class==article_class then -- local class matches article class or is blank

			show_quality = false -- hide quality class in project banner

			class = article_class

			if raw_args.class~='' and args.QUALITY_CRITERIA~='custom' then

				add_category('WikiProject banners with redundant class parameter')

			end

		elseif (article_class=='NA') and not isarticle(class) then -- article class and local class are both non-article classes

			show_quality = false

		else -- article class exists and differs from local class

			if args.QUALITY_CRITERIA~='custom' then

				conflict = true

				add_category(cfg.quality.conflict.category)

			end

		end

	end

	if not isarticle(class) then

		local cat =  mw.title.new(cfg.quality.assessment_category:format(class, assessment_cat))

		if not (cat.exists and #cat:getContent()>0) then --check if category exists and is not blank

			class = 'NA' -- automatically use NA for non-article pages if category does not exist

		end

	end

	local category = (class=='' and 'Unassessed' or class..'-Class') .. ' ' .. assessment_cat

	if show_quality then -- quality rating shown in banner

		local rating

		if pagetype=='article' then

			rating = class=='' and cfg.quality.not_yet or cfg.quality.rated:format(class)

		else

			rating = cfg.quality.not_required

		end

		local scale = args.QUALITY_CRITERIA=='custom'

			and assessment_link

			and cfg.quality.project_scale:format(wikilink(assessment_link..'#'..lang:ucfirst(cfg.quality.name), cfg.quality.name))

			or cfg.quality.default_scale

		local quality_rating = conflict and cfg.quality.conflict.text or cfg.quality.rating:format(pagetype, rating, scale)

		local colour = cfg.quality.colourclass or cfg.quality.colour.default

		local class_row =  mw.html.create('tr')

			:tag('td')

				:addClass('assess'):addClass('assess-' .. class)

				:css('background', colour):wikitext(wikilink(':Category:' .. category, class=='' and '???' or class))

				:css('border', conflict and cfg.quality.conflict.border or (cfg.quality.border..' '..colour))

			:done()

			:tag('td'):addClass('mbox-text'):attr('colspan', '2'):wikitext(quality_rating)

		:allDone()

		table.insert(rows, class_row)

		table.insert(

			nested_ratings,

			1,

			bubble(class=='' and 'Unassessed' or (class..'‑class'), colour, conflict)

		)

	end

	add_category(category)

end

if args.HOOK_ASSESS then

	table.insert(rows, args.HOOK_ASSESS)

end

if raw_args.b1 or raw_args.b2 or raw_args.b3 or raw_args.b4 or raw_args.b5 or raw_args.b6 then

	local b_checklist = require(cfg.auxiliary_module .. (sandbox or '')).b_checklist(args, raw_args, class, demo, assessment_link)

	table.insert(rows, b_checklist)

end

---------------------------

-- Importance assessment --

---------------------------

local importance = importance_mask(raw_args.importance or raw_args.priority, class, args.IMPORTANCE_SCALE, banner_name)

local importance_name = args.IMPN or (raw_args.priority and 'priority' or cfg.importance.default_name)

if importance then -- banner gives importance ratings

	local category = importance .. '-' .. importance_name .. ' ' .. assessment_cat

	if importance~='NA' then -- display importance rating

		local rating = importance=='Unknown' and cfg.importance.not_yet or cfg.importance.rated:format(importance, importance_name)

		local scale_name = cfg.importance.scale:format(importance_name)

		local scale = assessment_link

			and cfg.importance.project_scale:format(assessment_link..'#'..lang:ucfirst(scale_name), scale_name)

			or cfg.importance.default_scale

		local importance_rating = cfg.importance.rating:format(pagetype, rating, scale)

		local colour =  cfg.importance.colourimportance or cfg.importance.colour.default

		local importance_row =  mw.html.create('tr')

			:tag('td')

				:addClass('assess'):addClass('import'):addClass('import-' .. importance)

				:css('background', colour):wikitext(wikilink(':Category:' .. category, importance=='Unknown' and '???' or importance))

			:done()

			:tag('td'):addClass('mbox-text'):attr('colspan', '2'):wikitext(importance_rating)

		:allDone()

		table.insert(rows, importance_row)

		if importance~='Unknown' then -- importance is not NA or Unknown

			table.insert(

				nested_ratings,

				bubble(importance..'‑'..importance_name, colour)

			)

		end

	end

	add_category(category)

end

page_assessment(project, class, importance)

if args.HOOK_IMPORTANCE then

	table.insert(rows, args.HOOK_IMPORTANCE)

end

if args.QII_FORMAT then

	add_category(require(cfg.auxiliary_module .. (sandbox or '')).quality_importance_insection(args, class, importance, importance_name))

end

---------------------------

-- Collapsing sections ----

---------------------------

local collapse_section = function(collapse, new_rows, header)

	if collapse then

		local collapsed_section = mw.html.create('tr')

		local collapsed_rows = collapsed_section:tag('td')

			:attr('colspan','3'):addClass('wpb-collapsed-notes'):tag('table')

				:addClass('mw-collapsible mw-collapsed'):tag('tr')

					:tag('th')

						:attr('colspan','3'):addClass('wpb-collapsed-head'):wikitext(header)

					:done()

				:done()

				:tag('tr')

					:tag('td')

						:addClass('mbox-image wpb-gutter'):css('min-width',image_left_size):tag('span'):addClass('wpb-iefix'):wikitext('/&nbsp;'):

					done() --TO FIX IE

				:done()

				:tag('td'):done()

				:tag('td'):done()

			:done()

			for _, row in ipairs(new_rows) do

				collapsed_rows:node(row)

			end

		collapsed_section:allDone()

		table.insert(rows, collapsed_section)

	else

		for _, row in ipairs(new_rows) do

			table.insert(rows, row)

		end

	end

end

---------------------------

-- Task forces ------------

---------------------------

local nested_tf, taskforce_output = {}, {}

local tf_default_size = args.TF_SIZE or cfg.task_force.default_size

for _, k in ipairs(task_forces) do

	local tf_prefix = 'TF_' .. k .. '_'

	local tf_assessment_cat = argstf_prefix..'ASSESSMENT_CAT' or (argstf_prefix..'NAME' or '')..' articles'

	local tf_importance

	if raw_args'tf '..k..' importance' then

		tf_importance = importance_mask(raw_args'tf '..k..' importance'], class, args.IMPORTANCE_SCALE, banner_name)

		if tf_importance=='Unknown' and yesno(args.INHERIT_IMPORTANCE) then

			tf_importance = importance

		end

	end

	if argstf_prefix .. 'TEXT'~='none' then

		local portal = argstf_prefix..'PORTAL' and frame:expandTemplate{title='Portal', args={argstf_prefix .. 'PORTAL'], height='15', margin='0'}} or ''

		local text = ''

		local tf_text = argstf_prefix..'TEXT' or args.TF_TEXT

		if tf_text then

			text = portal .. tf_text

				:gsub('_NAME_', argstf_prefix .. 'NAME' or '')

				:gsub('_LINK_', argstf_prefix .. 'LINK' or '')

				:gsub('_IMPORTANCE_', tf_importance or '')

				:gsub('_PAGETYPE_', pagetype)

		else

			local tf_importance_text = tf_importance

				and tf_importance~='NA'

				and tf_importance~='Unknown'

				and ' ' .. cfg.task_force.importance:format(

					wikilink(':Category:' .. tf_importance .. '-' .. importance_name .. ' ' .. tf_assessment_cat, tf_importance .. '-' .. importance_name)

				) or ''

			text = portal .. cfg.task_force.text:format(

				pagetype,

				wikilink(argstf_prefix .. 'LINK'], argstf_prefix .. 'NAME']),

				tf_importance_text

			)

		end

		local tf_size = argstf_prefix .. 'SIZE' or tf_default_size

		local tf_image = ''

		if argstf_prefix .. 'IMAGE' then

			tf_image = image(argstf_prefix .. 'IMAGE'], tf_size, cfg.task_force.icon_alt, 'center')

		end

		local taskforce = mw.html.create('tr')

			:tag('td'):wikitext(tf_image):done()

			:tag('td'):addClass('mbox-text'):attr('colspan','2'):wikitext(text):allDone()

		table.insert(taskforce_output, taskforce)

	end

	if argstf_prefix..'HOOK' then

		table.insert(taskforce_output, argstf_prefix..'HOOK'])

	end

	if yesno(argstf_prefix..'QUALITY']) and class then

		local tf_class = check_exists(class, tf_assessment_cat)

		add_category((tf_class=='' and 'Unassessed' or tf_class..'-Class') .. ' ' .. tf_assessment_cat)

	end

	if tf_importance then

		add_category(tf_importance .. '-' .. importance_name .. ' ' .. tf_assessment_cat)

	end

	if argstf_prefix..'QII_FORMAT' then

		add_category(require(cfg.auxiliary_module .. (sandbox or '')).quality_importance_insection(args, class, tf_importance, importance_name, tf_prefix))

	end

	if argstf_prefix..'NAME' then

		page_assessment(project..'/'..argstf_prefix..'NAME'], class, tf_importance)

	end

	if argstf_prefix..'MAIN_CAT' then

		add_category(argstf_prefix..'MAIN_CAT'])

	end

	if argstf_prefix..'NESTED' then

		table.insert(nested_tf, wikilink(argstf_prefix..'LINK'], argstf_prefix..'NESTED']))

	end

	for _, c in ipairs(taskforce_categoriesk or {}) do-- add additional taskforce categories

		add_category(argstf_prefix..'CAT_'..c])

	end

end

if args.HOOK_TF then

	table.insert(taskforce_output, args.HOOK_TF)

end

local threshold = tonumber(args.TF_COLLAPSE) or (args.TF_HEADER and cfg.task_force.lower_threshold) or cfg.task_force.upper_threshold

collapse_section(

	#taskforce_output > threshold,

	taskforce_output,

	args.TF_HEADER or cfg.task_force.header

)

---------------------------

-- Notes ------------------

---------------------------

local note_output = {}

local note_default_size = args.NOTE_SIZE or args.NOTE_1_SIZE or cfg.note.default_size

local render_note = function(note_args)--text, image_name, size, category, sort_prefix

	local sort = note_args.sort_prefix and note_args.sort_prefix .. current_title.text

	add_category(note_args.category, sort)

	add_category(note_args.category2, sort)

	if note_args.text then

		local note_image = image(note_args.image_name, note_args.size or note_default_size, cfg.note.icon_alt, 'center')

		local new_note = mw.html.create('tr')

			:tag('td'):css('background', note_args.background):wikitext(note_image):done()

			:tag('td'):addClass('mbox-text'):attr('colspan', '2'):wikitext(note_args.text):allDone()

		table.insert(note_output, new_note)

		if note_image then

			local icon = mw.html.create('span')

				:addClass('wpb-header-bubbles')

				:wikitext('[[File:' .. note_args.image_name .. '|' .. cfg.note.header_icon .. '|' .. note_args.text .. '|link=|alt=]]')

				:done()

			table.insert(nested_ratings, tostring(icon))

		end

	end

end

local auto = false

local auto_arg = args.auto and args.auto:lower()

if (auto_arg=='yes' or auto_arg=='stub') and class=='Stub' then

	auto = 'stub'

elseif (auto_arg=='inherit' or auto_arg=='length') and class and class~='' then

	auto = auto_arg

end

if auto then

	local auto_cat = args.AUTO_ASSESS_CAT or cfg.auto.default_cat:format(project)

	local auto_text = cfg.auto.assessed:format(

		pagetype,

		cfg.autoauto], -- method of automatic assessment

		parameter_format('auto')

	)

	local sort_prefix

	if auto=='stub' then

		sort_prefix = 'S'

	elseif auto=='length' then

		sort_prefix = 'L'

	elseif auto=='inherit' then

		local sort_codes = cfg.auto.sort_codes

		sort_prefix = sort_codesclass or cfg.auto.default_sort_code

	end

	render_note{

		text = auto_text,

		image_name =  cfg.auto.icon,

		category = auto_cat,

		sort_prefix = sort_prefix

	}

end

if yesno(args.attention, true) then

	local attention_cat = args.ATTENTION_CAT or cfg.attention.default_cat:format(project)

	render_note{

		text = cfg.attention.text:format(pagetype),

		image_name = cfg.attention.icon,

		category = attention_cat

	}

end

if yesno(args.infobox, true) then

	local infobox_cat = args.INFOBOX_CAT or cfg.infobox.default_cat:format(project)

	render_note{

		text = cfg.infobox.text:format(pagetype),

		image_name = cfg.infobox.icon,

		category = infobox_cat

	}

end

for _, k in ipairs(notes) do

	local note_prefix = 'NOTE_' .. k .. '_'

	render_note{

		text = parse_text(argsnote_prefix..'TEXT']),

		image_name = argsnote_prefix..'IMAGE'],

		size = argsnote_prefix..'SIZE'],

		category = argsnote_prefix..'CAT'

	}

end

if yesno(args'image-needed'], true) then

	local image_needed_args = require(cfg.auxiliary_module .. (sandbox or '')).image_needed(args, pagetype)

	render_note(image_needed_args)

end

if yesno(args'collaboration-candidate'], true) or yesno(args'collaboration-current'], true) or yesno(args'collaboration-past'], true) then

	local collaboration_args = require(cfg.auxiliary_module .. (sandbox or '')).collaboration(args, pagetype, current_title)

	render_note(collaboration_args.candidate)

	render_note(collaboration_args.current)

	render_note(collaboration_args.past)

end

if yesno(args'a class'], true) then

	local a_class_args = require(cfg.auxiliary_module .. (sandbox or '')).a_class(args, lang)

	render_note(a_class_args)

end

if yesno(args'peer review'], true) or yesno(args'old peer review'], true) then

	local peer_review_args = require(cfg.auxiliary_module .. (sandbox or '')).peer_review(args, current_title)

	render_note(peer_review_args.current)

	render_note(peer_review_args.past)

end

local note_count = #note_output

if args.HOOK_NOTE then

	table.insert(note_output, args.HOOK_NOTE)

	local hook_collapsed = 0

	if args.HOOK_COLLAPSED then

		local success, result = pcall(mw.ext.ParserFunctions.expr, args.HOOK_COLLAPSED)

		hook_collapsed = success and tonumber(result) or 0

		if args.HOOK_COLLAPSED=='auto' then

			hook_collapsed = 1

		end

	end

	note_count = note_count + hook_collapsed

end

collapse_section(

	note_count > (tonumber(args.COLLAPSED) or cfg.note.threshold),

	note_output,

	args.COLLAPSED_HEAD or cfg.note.header

)

---------------------------

-- Bottom text ------------

---------------------------

if args.HOOK_BOTTOM then

	table.insert(rows, args.HOOK_BOTTOM)

end

if args.TODO_LINK or args.TODO_TEXT then

	local todolist = require(cfg.auxiliary_module .. (sandbox or '')).todo_list(args, frame)

	table.insert(rows, todolist)

end

if args.BOTTOM_TEXT then

	local bottom_text = mw.html.create('tr')

		bottom_text

			:tag('td')

			:attr('colspan','3')

			:wikitext(parse_text(args.BOTTOM_TEXT))

	:allDone()

	table.insert(rows, bottom_text)

end

if args.MAIN_CAT then

	add_category(args.MAIN_CAT)

end

---------------------------

-- Nested display ---------

---------------------------

if args.HOOK_NESTED then

	local hook_nested = args.HOOK_NESTED:gsub('^&#32;/ ', '') -- remove initial slash, will be added later

	table.insert(nested_tf, hook_nested)

end

local nested_tf_str = ''

if #nested_tf>0 then

	nested_tf_str = tostring(mw.html.create('span')

		:css('font-weight', 'normal')

		:wikitext(': ' .. table.concat(nested_tf, ' / '))

	)

end

local nested_ratings_str = #nested_ratings>0 and table.concat(nested_ratings, ' ') or ''

if args.HOOK_NESTED_ASSESS then

	nested_ratings_str = nested_ratings_str .. tostring(mw.html.create('span')

		:addClass('wpb-header-bubbles')

		:wikitext(args.HOOK_NESTED_ASSESS)

	)

end

local header_row = mw.html.create('tr')

	:addClass('wpb-header')

	:tag('td')

		:addClass('wpb-header-icon')

		:attr('width', '50px')

		:css('text-align', 'center')

		:wikitext(image(args.IMAGE_LEFT, cfg.image.header_size, cfg.image.alt))

	:done()

	:tag('td')

		:addClass('wpb-header-combined')

		:wikitext(wikilink(project_link.prefixedText, project) .. nested_tf_str .. '  ' .. nested_ratings_str)

	:allDone()

---------------------------

-- Prepare categories -----

---------------------------

local categories_formatted = ''

if args.demo_page then -- for testing purposes

	local category_list = mw.html.create('div')

		:css('background-color', '#F5F5F5'):css('border-width', '1px')

		:css('width', '500px')

		:wikitext('Categories:')

		:tag('ul')

	for _, cat in ipairs(categories) do

		local cat_link = wikilink(':Category:' .. cat.category, cat.category)

		category_list:tag('li'):wikitext(cat_link):done()

	end

	categories_formatted = tostring(category_list:allDone())

elseif not demo then

	local categories_linked = {}

	for _, cat in ipairs(categories) do

		local cat_link = wikilink('Category:' .. cat.category, cat.key)

		table.insert(categories_linked, cat_link)

	end

	categories_formatted = table.concat(categories_linked)

end

---------------------------

-- Make banner ------------

---------------------------

local status_class = (cfg.statusargs.PROJECT_STATUS or cfg.status.default_active) .. cfg.status.suffix

local banner = mw.html.create('table')

local banner_rows = banner

	:addClass('tmbox tmbox-notice mw-collapsible innercollapse wpb ' .. status_class)

	:css('table-layout', 'fixed')

	:node(header_row)

	:tag('tr')

		:tag('td')

			:addClass('mbox-text wpb-main')

			:attr('colspan','2')

			:tag('table')

				for _, row in ipairs(rows) do

					banner_rows:node(row)

				end

if args.listas then

	frame:preprocess('{{DEFAULTSORT:' .. args.listas .. '}}')

end

local tstyle = frame:extensionTag ('templatestyles', '', {src='Module:Message box/tmbox.css'}) ..

	frame:extensionTag ('templatestyles', '', {src = 'Module:WikiProject banner' .. (sandbox or '') .. '/styles.css'})

return warning .. tstyle .. tostring(banner) .. categories_formatted, note_count, #taskforce_output, assessment_link

end



local parameter_check = function(frame, banner_name, project_name)

---------------------------

-- Unknown parameters -----

---------------------------

local parent_args = args_module.getArgs(frame, {parentOnly = true})

local parameters = {}

for parameter in banner_name:getContent():gmatch('{{{([^|}]+)') do

	table.insert(parameters, parameter)

end

parameters.preview = cfg.unknown_parameters.preview:format(wikilink(banner_name.fullText))

local unknown_category = cfg.unknown_parameters.tracking:format(project_name)

if not mw.title.new(unknown_category).exists then

	unknown_category = cfg.unknown_parameters.default

end

parameters.unknown = unknown_category and '[[' .. unknown_category .. '|_VALUE_]]' or ''

return require('Module:Check for unknown parameters')._check(parameters, parent_args)

end



local initialise = function(args, raw_args, inactive)

	args.demo_page = args_module.getArgs(frame, {parentOnly = true}).demo_page

	local project_name = args.PROJECT_NAME or 'WikiProject ' .. (args.PROJECT or 'PROJECT')

	local banner_name = mw.title.new(args.BANNER_NAME or 'Template:WikiProject ' .. (args.PROJECT or 'PROJECT'))

	local demo = not yesno(args.category or true, true) or args.demo_page

	local on_template_page = not demo and current_title.rootPageTitle==banner_name.rootPageTitle

	local unknown_parameters = banner_name.exists and not demo and parameter_check(frame, banner_name, project_name) or ''

	if on_template_page then

		local templatepage = require('Module:WikiProject banner/templatepage' .. (sandbox or '')).templatepage

		return templatepage(args, raw_args, inactive)

	else

		return unknown_parameters .. p._main(args, raw_args, demo or inactive, banner_name), nil -- nil to disregard subsequent returned values

	end

end



p.main = function(frame)

	local args = args_module.getArgs(frame, {frameOnly = true})

	local raw_args = args_module.getArgs(frame, {frameOnly = true, removeBlanks = false})

	return initialise(args, raw_args)

end



p.inactive = function(frame)

	local args = args_module.getArgs(frame, {frameOnly = true})

	local project_name = args.PROJECT_NAME or 'WikiProject ' .. (args.PROJECT or 'PROJECT')

	local project_link = mw.title.new(args.PROJECT_LINK or 'Wikipedia:' .. project_name)

	local _status = cfg.statusargs.PROJECT_STATUS or cfg.status.default_inactive

	local main_text = cfg.inactive.text:format(

		'_PAGETYPE_',

		project_link.prefixedText,

		project_name,

		_status

	)

	return initialise({

			PROJECT = args.PROJECT,

			PROJECT_STATUS = _status,

			BANNER_NAME = args.BANNER_NAME,

			IMAGE_LEFT = cfg.inactive.image,

			IMAGE_LEFT_SIZE = cfg.inactive.image_size,

			MAIN_TEXT = main_text,

			HOOK_NESTED_ASSESS = ' ' .. cfg.inactive.nested:format(_status),

			substcheck = args.substcheck,

			category = args.category

		},

		{

			class = frame.args.class,

			substcheck = '' -- to prevent warning on templatepage

		},

		true -- to prevent categorisation

	), nil

end



return p
Permanently protected module
From Wikipedia, the free encyclopedia


require('strict')

local p = {}

local sandbox-- = '/sandbox'

local cfg = mw.loadData('Module:WikiProject banner/config' .. (sandbox or ''))

local args_module = require('Module:Arguments')

local mbox = require('Module:Message box').main

local yesno = require('Module:Yesno')

local frame = mw.getCurrentFrame()

local lang = mw.getLanguage(cfg.language)

local current_title = mw.title.getCurrentTitle()

local parameter_format = function(parameter, value)

	return frame:expandTemplate{title='para', args={parameter, value or ''}}

end



local wikilink = function(link, display)

	if link then

		return display and '[['..link..'|'..display..']]' or '[['..link..']]'

	else

		return display or ''

	end

end



local image = function(image_name, size, alt, position)

	return image_name and '[[File:'

		.. image_name

		.. (size and '|' .. size or '')

		.. (position and '|' .. position or '')

		.. (alt and '|alt=' .. alt or '')

		.. ']]'

end



local if_exists = function(target, fallback) -- function to add wikilink if target exists

	local title = mw.title.new(target)

	if title and title.exists then

		return wikilink(target)

	else

		return fallback or target

	end

end



local isarticle = function(class)

	local article = true

	for _,v in ipairs(cfg.quality.non_article_classes) do

		if class==v then -- class matches one of the non-article classes

			article = false

			break

		end

	end

	return article

end



---------------------------

-- Importance mask --------

---------------------------

local importance_mask = function(raw_importance, class, scale, banner_name)

	local importance

	if scale=='inline' then -- pass importance without change

		importance = raw_importance

	elseif scale=='subpage' then

		local custom_mask = banner_name:subPageTitle('importance')

		if custom_mask.exists and #custom_mask:getContent()>1 then -- pass to custom importance mask

			importance = mw.text.trim(frame:expandTemplate{

				title = custom_mask.prefixedText,

				args = {importance=raw_importance or '¬', class=class}

			})

		end

	else

		importance = frame:expandTemplate{

			title = 'Template:Importance mask',

			args = {raw_importance or '¬', class=class}}

	end

	if importance=='¬' then

		importance = nil

	end

	return importance

end



---------------------------

-- Quality class mask -----

---------------------------

p.readarticleclass = function(options, page) -- used by _main and also Module:Banner shell

	page = page or current_title.prefixedText

	local get_parameter_value = require('Module:Template parameter value').getValue

	local success, result = get_parameter_value(page, cfg.WPBS_redirects, 'class', options)

	return success and result

	-- returns FALSE if banner shell template does not exist on page

	-- returns BLANK if class parameter is not defined or is defined blank

	-- otherwise returns class parameter

end

p.class_mask = function(class, title, FQS, pagetype)

	local resolveFQSgrade = function(class)

		return FQS and lang:ucfirst(class) or 'NA'

	end

	local out = '' -- default to unassessed

	title = title or mw.title.getCurrentTitle()

	local ns = title.namespace

	class = class:match('^%s*(.-)%s*$'):lower()

	if pagetype=='redirect' or pagetype=='soft redirect' then

		out = resolveFQSgrade('redirect')

	elseif ns==1 then -- Talk

		if pagetype=='disambiguation page' or class=='dab' or class=='disambig' or class=='disambiguation' or class=='disamb' then

			out = resolveFQSgrade('disambig')

		elseif class=='start' or class=='stub' then -- Ucfirst

			out = lang:ucfirst(class)

		elseif class=='b' or class=='c' or class=='fa' or class=='fl' or class=='a' or class=='ga' then -- Upper-case

			out = class:upper()

		elseif class=='list' or class=='sia' or class=='si' or class=='sl' then-- List

			out = 'List'

		end

	elseif ns==7 or ns==711 then -- File talk

		if class=='fm' and FQS then

			out = 'FM'

		else

			out = resolveFQSgrade('file')

		end

	elseif ns==15 then -- Category talk

		out = resolveFQSgrade('category')

	elseif ns==101 then -- Portal talk

		out = resolveFQSgrade('portal')

	elseif ns==11 or ns==829 then -- Template talk

		out = resolveFQSgrade('template')

	elseif ns==5 then -- Wikipedia talk

		out = resolveFQSgrade('project')

	elseif ns==119 then -- Draft talk

		out = resolveFQSgrade('draft')

	else

		out = 'NA'

	end

	return out

end



local page_assessment = function(project, class, importance) -- add PageAssessments parser function

	local assessment = table.concat({project, class or '', importance or ''},'|')

	frame:preprocess('{{#assessment:' .. assessment .. '}}')

end



local bubble = function(text, colour, conflict)

	local out = mw.html.create('span')

		:addClass('wpb-header-bubbles')

		:css('background', colour)

		:css('color', '#222' )

		:css('border', conflict and cfg.quality.conflict.border or (cfg.quality.border..' '..colour))

		:wikitext(text)

	return tostring(out)

end



p._main = function(args, raw_args, demo, banner_name)

---------------------------

-- Initialise parameters --

---------------------------

local project = args.PROJECT or 'PROJECT'

local project_name = args.PROJECT_NAME or 'WikiProject ' .. project

local project_link = mw.title.new(args.PROJECT_LINK or 'Wikipedia:' .. project_name)

local pagetype = demo and not args.demo_page and 'article' or require('Module:Pagetype' .. (sandbox or ''))._main({

	page = args.demo_page,

	dab = 'disambiguation page'

})

local rows, nested_ratings, task_forces, notes, categories, taskforce_categories = {}, {}, {}, {}, {}, {}

local add_category = function(category, key)

	if category and category~='none' then

		table.insert(categories, {category = category, key = key})

	end

end

local parse_text = function(text)

	return text and text:gsub('_PAGETYPE_', pagetype)

end

for arg_name, arg_value in pairs(args) do

	local tf_match = mw.ustring.match(arg_name,'^tf (%d+)$')

	local note_match = mw.ustring.match(arg_name,'^note (%d+)$')

	if tf_match and yesno(arg_value, true) then

		table.insert(task_forces, tf_match)

	elseif note_match and yesno(arg_value, true) then

		table.insert(notes, note_match)

	else

		local tf, cat = mw.ustring.match(arg_name,'^tf (%d+) cat (%d+)$')

		if tf and yesno(arg_value, true) then

			if not taskforce_categoriestf then -- initialise table

				taskforce_categoriestf = {}

			end

			table.insert(taskforce_categoriestf], cat)

		end

	end

end

table.sort(task_forces, function (x, y) return tonumber(x) < tonumber(y) end)

table.sort(notes, function (x, y) return tonumber(x) < tonumber(y) end)

local warning = ''

---------------------------

-- Location warning -------

---------------------------

local show_namespace_warning = not (current_title.isTalkPage or demo)

if show_namespace_warning then

	local text = cfg.namespace_warning.text:format(

		pagetype,

		current_title.talkPageTitle.fullText,

		parameter_format('category', 'no')

	)

	local sortkey = current_title.namespace==10 and cfg.namespace_warning.sortkey_on_template_page or cfg.namespace_warning.sortkey

	if current_title.namespace==10 then -- on the Template namespace

		text = text .. '  ' .. cfg.namespace_warning.on_template_page:format(

			parameter_format('BANNER_NAME'),

			current_title.prefixedText

		)

	end

	warning = mbox('ombox', {

		image = '[[File:' .. cfg.namespace_warning.image .. '|40px]]',

		type = cfg.namespace_warning.type_,

		text = text

	})

	if not current_title.subjectPageTitle:inNamespace(2) then

		add_category(cfg.namespace_warning.categories, sortkey)

	end

end

---------------------------

-- Substitution warning ---

---------------------------

if args.substcheck=='SUBST' then

	local text = cfg.subst_warning.text:format(

		project_name,

		'<code>&#123;&#123;'..banner_name.prefixedText..'&#125;&#125;</code>'

	)

	warning = warning .. mbox('ombox', {

		image = '[[File:' .. cfg.subst_warning.image .. '|40px]]',

		type = cfg.subst_warning.type_,

		text = text,

	}) .. cfg.subst_warning.categories

end

---------------------------

-- Primary image/text -----

---------------------------

local assessment_cat = args.ASSESSMENT_CAT or project .. ' articles'

local primary_image = function(image_name, size)

	local cell = mw.html.create('td')

	if image_name and image_name~='' then

		cell:addClass('mbox-image wpb-image')

		:wikitext(image(image_name, size, cfg.image.alt))

	else

		cell:addClass('mbox-empty-cell')

	end

	cell:done()

	return cell

end

local portal = args.PORTAL

local portal_box = portal and frame:expandTemplate{title='Portal', args={portal}} or ''

local main_text = portal_box .. (parse_text(args.MAIN_TEXT) or cfg.main_text:format(

	pagetype,

	project_link.prefixedText,

	project_name,

	args.MAIN_ARTICLE and if_exists(args.MAIN_ARTICLE) or if_exists(project, project .. ' articles'),

	project_link.talkPageTitle.prefixedText

))

local image_left_size = args.IMAGE_LEFT_SIZE or cfg.image.default_size

local primary_row = mw.html.create('tr')

	:node(primary_image(args.IMAGE_LEFT, image_left_size))

	:tag('td')

		:addClass('mbox-text')

		:wikitext(main_text)

		:tag('span')

			:addClass('metadata wpb-metadata')

			:tag('span'):addClass('wpb-project'):wikitext(project):done()

			:tag('span'):addClass('wpb-project_link'):wikitext(project_link.prefixedText):done()

			:tag('span'):addClass('wpb-banner_name'):wikitext(banner_name.prefixedText):done()

			:tag('span'):addClass('wpb-assessment_cat'):wikitext(assessment_cat):done()

		:done()

	:done()	

	:node(primary_image(args.IMAGE_RIGHT, args.IMAGE_RIGHT_SIZE or cfg.image.default_size))

:done()

table.insert(rows, primary_row)

---------------------------

-- Quality assessment -----

---------------------------

local assessment_link = args.ASSESSMENT_LINK

if not assessment_link then

	local fallback = mw.title.new(project_link.prefixedText .. '/Assessment')

	assessment_link = fallback.exists and fallback.prefixedText

elseif assessment_link=='no' then

	assessment_link = nil

end

local check_exists = function(class, assessment_cat) -- check if category exists and is not blank

	if not isarticle(class) then

		local cat =  mw.title.new('Category:' .. class .. '-Class' .. ' ' .. assessment_cat)

		return (cat.exists and #cat:getContent()>0) and class or 'NA' -- automatically use NA for non-article pages if category does not exist

	else

		return class

	end

end

local class = raw_args.class

if class then -- banner gives quality ratings

	local title = args.demo_page and mw.title.new(args.demo_page) or current_title

	local article_class = p.readarticleclass({ignore_subtemplates=true}, title.prefixedText)

	if not article_class then

		if pagetype=='article' then

			add_category('Articles with WikiProject banners but without a banner shell')

		else

			add_category('WikiProject banners without banner shells')

		end

	end

	article_class = article_class and p.class_mask(article_class, title, false, pagetype)

	local show_quality, conflict = true, false

	if args.QUALITY_CRITERIA=='custom' then -- project has opted out of standard assessment scale and uses a custom mask

		local custom_mask = banner_name:subPageTitle('class')

		if custom_mask.exists and #custom_mask:getContent()>1 then

			raw_args.demo_page = args.demo_page -- send demo_page to custom mask

			class = mw.text.trim(frame:expandTemplate{

				title = custom_mask.prefixedText,

				args = raw_args

			})

			if class=='' and article_class and article_class~='' then -- if unassessed and article class exists, check if it can be inherited

				local new_arg_table = {}

				for arg, val in pairs(raw_args) do -- construct new argument table to send to custom mask

					new_arg_tablearg = val

				end

				new_arg_table.class = article_class -- replace class with inherited class

				local article_class_normalised = mw.text.trim(frame:expandTemplate{

					title = custom_mask.prefixedText,

					args = new_arg_table

				})

				if article_class_normalised and article_class_normalised~='' then

					class = article_class_normalised -- inherit class from article_class normalised by custom mask

				else

					article_class = nil -- effectively no article_class for this banner

				end

			end

		end

	else

		class = p.class_mask(class, title, true, pagetype)

	end

	if article_class then -- banner shell exists

		if article_class=='' then -- no article class defined

			if class=='' then -- local class also does not exist, check whether any other class parameters are defined inside the shell

				local classparam = p.readarticleclass({ignore_blank=true, only_subtemplates=true}, title.prefixedText)

				if classparam=='' then -- no class parameters defined, display as globally unassessed

					show_quality = false -- hide quality class in project banner

				end

			else

				add_category('Pages using WikiProject banner shell without a project-independent quality rating')

			end

		elseif class=='' or class==article_class then -- local class matches article class or is blank

			show_quality = false -- hide quality class in project banner

			class = article_class

			if raw_args.class~='' and args.QUALITY_CRITERIA~='custom' then

				add_category('WikiProject banners with redundant class parameter')

			end

		elseif (article_class=='NA') and not isarticle(class) then -- article class and local class are both non-article classes

			show_quality = false

		else -- article class exists and differs from local class

			if args.QUALITY_CRITERIA~='custom' then

				conflict = true

				add_category(cfg.quality.conflict.category)

			end

		end

	end

	if not isarticle(class) then

		local cat =  mw.title.new(cfg.quality.assessment_category:format(class, assessment_cat))

		if not (cat.exists and #cat:getContent()>0) then --check if category exists and is not blank

			class = 'NA' -- automatically use NA for non-article pages if category does not exist

		end

	end

	local category = (class=='' and 'Unassessed' or class..'-Class') .. ' ' .. assessment_cat

	if show_quality then -- quality rating shown in banner

		local rating

		if pagetype=='article' then

			rating = class=='' and cfg.quality.not_yet or cfg.quality.rated:format(class)

		else

			rating = cfg.quality.not_required

		end

		local scale = args.QUALITY_CRITERIA=='custom'

			and assessment_link

			and cfg.quality.project_scale:format(wikilink(assessment_link..'#'..lang:ucfirst(cfg.quality.name), cfg.quality.name))

			or cfg.quality.default_scale

		local quality_rating = conflict and cfg.quality.conflict.text or cfg.quality.rating:format(pagetype, rating, scale)

		local colour = cfg.quality.colourclass or cfg.quality.colour.default

		local class_row =  mw.html.create('tr')

			:tag('td')

				:addClass('assess'):addClass('assess-' .. class)

				:css('background', colour):wikitext(wikilink(':Category:' .. category, class=='' and '???' or class))

				:css('border', conflict and cfg.quality.conflict.border or (cfg.quality.border..' '..colour))

			:done()

			:tag('td'):addClass('mbox-text'):attr('colspan', '2'):wikitext(quality_rating)

		:allDone()

		table.insert(rows, class_row)

		table.insert(

			nested_ratings,

			1,

			bubble(class=='' and 'Unassessed' or (class..'‑class'), colour, conflict)

		)

	end

	add_category(category)

end

if args.HOOK_ASSESS then

	table.insert(rows, args.HOOK_ASSESS)

end

if raw_args.b1 or raw_args.b2 or raw_args.b3 or raw_args.b4 or raw_args.b5 or raw_args.b6 then

	local b_checklist = require(cfg.auxiliary_module .. (sandbox or '')).b_checklist(args, raw_args, class, demo, assessment_link)

	table.insert(rows, b_checklist)

end

---------------------------

-- Importance assessment --

---------------------------

local importance = importance_mask(raw_args.importance or raw_args.priority, class, args.IMPORTANCE_SCALE, banner_name)

local importance_name = args.IMPN or (raw_args.priority and 'priority' or cfg.importance.default_name)

if importance then -- banner gives importance ratings

	local category = importance .. '-' .. importance_name .. ' ' .. assessment_cat

	if importance~='NA' then -- display importance rating

		local rating = importance=='Unknown' and cfg.importance.not_yet or cfg.importance.rated:format(importance, importance_name)

		local scale_name = cfg.importance.scale:format(importance_name)

		local scale = assessment_link

			and cfg.importance.project_scale:format(assessment_link..'#'..lang:ucfirst(scale_name), scale_name)

			or cfg.importance.default_scale

		local importance_rating = cfg.importance.rating:format(pagetype, rating, scale)

		local colour =  cfg.importance.colourimportance or cfg.importance.colour.default

		local importance_row =  mw.html.create('tr')

			:tag('td')

				:addClass('assess'):addClass('import'):addClass('import-' .. importance)

				:css('background', colour):wikitext(wikilink(':Category:' .. category, importance=='Unknown' and '???' or importance))

			:done()

			:tag('td'):addClass('mbox-text'):attr('colspan', '2'):wikitext(importance_rating)

		:allDone()

		table.insert(rows, importance_row)

		if importance~='Unknown' then -- importance is not NA or Unknown

			table.insert(

				nested_ratings,

				bubble(importance..'‑'..importance_name, colour)

			)

		end

	end

	add_category(category)

end

page_assessment(project, class, importance)

if args.HOOK_IMPORTANCE then

	table.insert(rows, args.HOOK_IMPORTANCE)

end

if args.QII_FORMAT then

	add_category(require(cfg.auxiliary_module .. (sandbox or '')).quality_importance_insection(args, class, importance, importance_name))

end

---------------------------

-- Collapsing sections ----

---------------------------

local collapse_section = function(collapse, new_rows, header)

	if collapse then

		local collapsed_section = mw.html.create('tr')

		local collapsed_rows = collapsed_section:tag('td')

			:attr('colspan','3'):addClass('wpb-collapsed-notes'):tag('table')

				:addClass('mw-collapsible mw-collapsed'):tag('tr')

					:tag('th')

						:attr('colspan','3'):addClass('wpb-collapsed-head'):wikitext(header)

					:done()

				:done()

				:tag('tr')

					:tag('td')

						:addClass('mbox-image wpb-gutter'):css('min-width',image_left_size):tag('span'):addClass('wpb-iefix'):wikitext('/&nbsp;'):

					done() --TO FIX IE

				:done()

				:tag('td'):done()

				:tag('td'):done()

			:done()

			for _, row in ipairs(new_rows) do

				collapsed_rows:node(row)

			end

		collapsed_section:allDone()

		table.insert(rows, collapsed_section)

	else

		for _, row in ipairs(new_rows) do

			table.insert(rows, row)

		end

	end

end

---------------------------

-- Task forces ------------

---------------------------

local nested_tf, taskforce_output = {}, {}

local tf_default_size = args.TF_SIZE or cfg.task_force.default_size

for _, k in ipairs(task_forces) do

	local tf_prefix = 'TF_' .. k .. '_'

	local tf_assessment_cat = argstf_prefix..'ASSESSMENT_CAT' or (argstf_prefix..'NAME' or '')..' articles'

	local tf_importance

	if raw_args'tf '..k..' importance' then

		tf_importance = importance_mask(raw_args'tf '..k..' importance'], class, args.IMPORTANCE_SCALE, banner_name)

		if tf_importance=='Unknown' and yesno(args.INHERIT_IMPORTANCE) then

			tf_importance = importance

		end

	end

	if argstf_prefix .. 'TEXT'~='none' then

		local portal = argstf_prefix..'PORTAL' and frame:expandTemplate{title='Portal', args={argstf_prefix .. 'PORTAL'], height='15', margin='0'}} or ''

		local text = ''

		local tf_text = argstf_prefix..'TEXT' or args.TF_TEXT

		if tf_text then

			text = portal .. tf_text

				:gsub('_NAME_', argstf_prefix .. 'NAME' or '')

				:gsub('_LINK_', argstf_prefix .. 'LINK' or '')

				:gsub('_IMPORTANCE_', tf_importance or '')

				:gsub('_PAGETYPE_', pagetype)

		else

			local tf_importance_text = tf_importance

				and tf_importance~='NA'

				and tf_importance~='Unknown'

				and ' ' .. cfg.task_force.importance:format(

					wikilink(':Category:' .. tf_importance .. '-' .. importance_name .. ' ' .. tf_assessment_cat, tf_importance .. '-' .. importance_name)

				) or ''

			text = portal .. cfg.task_force.text:format(

				pagetype,

				wikilink(argstf_prefix .. 'LINK'], argstf_prefix .. 'NAME']),

				tf_importance_text

			)

		end

		local tf_size = argstf_prefix .. 'SIZE' or tf_default_size

		local tf_image = ''

		if argstf_prefix .. 'IMAGE' then

			tf_image = image(argstf_prefix .. 'IMAGE'], tf_size, cfg.task_force.icon_alt, 'center')

		end

		local taskforce = mw.html.create('tr')

			:tag('td'):wikitext(tf_image):done()

			:tag('td'):addClass('mbox-text'):attr('colspan','2'):wikitext(text):allDone()

		table.insert(taskforce_output, taskforce)

	end

	if argstf_prefix..'HOOK' then

		table.insert(taskforce_output, argstf_prefix..'HOOK'])

	end

	if yesno(argstf_prefix..'QUALITY']) and class then

		local tf_class = check_exists(class, tf_assessment_cat)

		add_category((tf_class=='' and 'Unassessed' or tf_class..'-Class') .. ' ' .. tf_assessment_cat)

	end

	if tf_importance then

		add_category(tf_importance .. '-' .. importance_name .. ' ' .. tf_assessment_cat)

	end

	if argstf_prefix..'QII_FORMAT' then

		add_category(require(cfg.auxiliary_module .. (sandbox or '')).quality_importance_insection(args, class, tf_importance, importance_name, tf_prefix))

	end

	if argstf_prefix..'NAME' then

		page_assessment(project..'/'..argstf_prefix..'NAME'], class, tf_importance)

	end

	if argstf_prefix..'MAIN_CAT' then

		add_category(argstf_prefix..'MAIN_CAT'])

	end

	if argstf_prefix..'NESTED' then

		table.insert(nested_tf, wikilink(argstf_prefix..'LINK'], argstf_prefix..'NESTED']))

	end

	for _, c in ipairs(taskforce_categoriesk or {}) do-- add additional taskforce categories

		add_category(argstf_prefix..'CAT_'..c])

	end

end

if args.HOOK_TF then

	table.insert(taskforce_output, args.HOOK_TF)

end

local threshold = tonumber(args.TF_COLLAPSE) or (args.TF_HEADER and cfg.task_force.lower_threshold) or cfg.task_force.upper_threshold

collapse_section(

	#taskforce_output > threshold,

	taskforce_output,

	args.TF_HEADER or cfg.task_force.header

)

---------------------------

-- Notes ------------------

---------------------------

local note_output = {}

local note_default_size = args.NOTE_SIZE or args.NOTE_1_SIZE or cfg.note.default_size

local render_note = function(note_args)--text, image_name, size, category, sort_prefix

	local sort = note_args.sort_prefix and note_args.sort_prefix .. current_title.text

	add_category(note_args.category, sort)

	add_category(note_args.category2, sort)

	if note_args.text then

		local note_image = image(note_args.image_name, note_args.size or note_default_size, cfg.note.icon_alt, 'center')

		local new_note = mw.html.create('tr')

			:tag('td'):css('background', note_args.background):wikitext(note_image):done()

			:tag('td'):addClass('mbox-text'):attr('colspan', '2'):wikitext(note_args.text):allDone()

		table.insert(note_output, new_note)

		if note_image then

			local icon = mw.html.create('span')

				:addClass('wpb-header-bubbles')

				:wikitext('[[File:' .. note_args.image_name .. '|' .. cfg.note.header_icon .. '|' .. note_args.text .. '|link=|alt=]]')

				:done()

			table.insert(nested_ratings, tostring(icon))

		end

	end

end

local auto = false

local auto_arg = args.auto and args.auto:lower()

if (auto_arg=='yes' or auto_arg=='stub') and class=='Stub' then

	auto = 'stub'

elseif (auto_arg=='inherit' or auto_arg=='length') and class and class~='' then

	auto = auto_arg

end

if auto then

	local auto_cat = args.AUTO_ASSESS_CAT or cfg.auto.default_cat:format(project)

	local auto_text = cfg.auto.assessed:format(

		pagetype,

		cfg.autoauto], -- method of automatic assessment

		parameter_format('auto')

	)

	local sort_prefix

	if auto=='stub' then

		sort_prefix = 'S'

	elseif auto=='length' then

		sort_prefix = 'L'

	elseif auto=='inherit' then

		local sort_codes = cfg.auto.sort_codes

		sort_prefix = sort_codesclass or cfg.auto.default_sort_code

	end

	render_note{

		text = auto_text,

		image_name =  cfg.auto.icon,

		category = auto_cat,

		sort_prefix = sort_prefix

	}

end

if yesno(args.attention, true) then

	local attention_cat = args.ATTENTION_CAT or cfg.attention.default_cat:format(project)

	render_note{

		text = cfg.attention.text:format(pagetype),

		image_name = cfg.attention.icon,

		category = attention_cat

	}

end

if yesno(args.infobox, true) then

	local infobox_cat = args.INFOBOX_CAT or cfg.infobox.default_cat:format(project)

	render_note{

		text = cfg.infobox.text:format(pagetype),

		image_name = cfg.infobox.icon,

		category = infobox_cat

	}

end

for _, k in ipairs(notes) do

	local note_prefix = 'NOTE_' .. k .. '_'

	render_note{

		text = parse_text(argsnote_prefix..'TEXT']),

		image_name = argsnote_prefix..'IMAGE'],

		size = argsnote_prefix..'SIZE'],

		category = argsnote_prefix..'CAT'

	}

end

if yesno(args'image-needed'], true) then

	local image_needed_args = require(cfg.auxiliary_module .. (sandbox or '')).image_needed(args, pagetype)

	render_note(image_needed_args)

end

if yesno(args'collaboration-candidate'], true) or yesno(args'collaboration-current'], true) or yesno(args'collaboration-past'], true) then

	local collaboration_args = require(cfg.auxiliary_module .. (sandbox or '')).collaboration(args, pagetype, current_title)

	render_note(collaboration_args.candidate)

	render_note(collaboration_args.current)

	render_note(collaboration_args.past)

end

if yesno(args'a class'], true) then

	local a_class_args = require(cfg.auxiliary_module .. (sandbox or '')).a_class(args, lang)

	render_note(a_class_args)

end

if yesno(args'peer review'], true) or yesno(args'old peer review'], true) then

	local peer_review_args = require(cfg.auxiliary_module .. (sandbox or '')).peer_review(args, current_title)

	render_note(peer_review_args.current)

	render_note(peer_review_args.past)

end

local note_count = #note_output

if args.HOOK_NOTE then

	table.insert(note_output, args.HOOK_NOTE)

	local hook_collapsed = 0

	if args.HOOK_COLLAPSED then

		local success, result = pcall(mw.ext.ParserFunctions.expr, args.HOOK_COLLAPSED)

		hook_collapsed = success and tonumber(result) or 0

		if args.HOOK_COLLAPSED=='auto' then

			hook_collapsed = 1

		end

	end

	note_count = note_count + hook_collapsed

end

collapse_section(

	note_count > (tonumber(args.COLLAPSED) or cfg.note.threshold),

	note_output,

	args.COLLAPSED_HEAD or cfg.note.header

)

---------------------------

-- Bottom text ------------

---------------------------

if args.HOOK_BOTTOM then

	table.insert(rows, args.HOOK_BOTTOM)

end

if args.TODO_LINK or args.TODO_TEXT then

	local todolist = require(cfg.auxiliary_module .. (sandbox or '')).todo_list(args, frame)

	table.insert(rows, todolist)

end

if args.BOTTOM_TEXT then

	local bottom_text = mw.html.create('tr')

		bottom_text

			:tag('td')

			:attr('colspan','3')

			:wikitext(parse_text(args.BOTTOM_TEXT))

	:allDone()

	table.insert(rows, bottom_text)

end

if args.MAIN_CAT then

	add_category(args.MAIN_CAT)

end

---------------------------

-- Nested display ---------

---------------------------

if args.HOOK_NESTED then

	local hook_nested = args.HOOK_NESTED:gsub('^&#32;/ ', '') -- remove initial slash, will be added later

	table.insert(nested_tf, hook_nested)

end

local nested_tf_str = ''

if #nested_tf>0 then

	nested_tf_str = tostring(mw.html.create('span')

		:css('font-weight', 'normal')

		:wikitext(': ' .. table.concat(nested_tf, ' / '))

	)

end

local nested_ratings_str = #nested_ratings>0 and table.concat(nested_ratings, ' ') or ''

if args.HOOK_NESTED_ASSESS then

	nested_ratings_str = nested_ratings_str .. tostring(mw.html.create('span')

		:addClass('wpb-header-bubbles')

		:wikitext(args.HOOK_NESTED_ASSESS)

	)

end

local header_row = mw.html.create('tr')

	:addClass('wpb-header')

	:tag('td')

		:addClass('wpb-header-icon')

		:attr('width', '50px')

		:css('text-align', 'center')

		:wikitext(image(args.IMAGE_LEFT, cfg.image.header_size, cfg.image.alt))

	:done()

	:tag('td')

		:addClass('wpb-header-combined')

		:wikitext(wikilink(project_link.prefixedText, project) .. nested_tf_str .. '  ' .. nested_ratings_str)

	:allDone()

---------------------------

-- Prepare categories -----

---------------------------

local categories_formatted = ''

if args.demo_page then -- for testing purposes

	local category_list = mw.html.create('div')

		:css('background-color', '#F5F5F5'):css('border-width', '1px')

		:css('width', '500px')

		:wikitext('Categories:')

		:tag('ul')

	for _, cat in ipairs(categories) do

		local cat_link = wikilink(':Category:' .. cat.category, cat.category)

		category_list:tag('li'):wikitext(cat_link):done()

	end

	categories_formatted = tostring(category_list:allDone())

elseif not demo then

	local categories_linked = {}

	for _, cat in ipairs(categories) do

		local cat_link = wikilink('Category:' .. cat.category, cat.key)

		table.insert(categories_linked, cat_link)

	end

	categories_formatted = table.concat(categories_linked)

end

---------------------------

-- Make banner ------------

---------------------------

local status_class = (cfg.statusargs.PROJECT_STATUS or cfg.status.default_active) .. cfg.status.suffix

local banner = mw.html.create('table')

local banner_rows = banner

	:addClass('tmbox tmbox-notice mw-collapsible innercollapse wpb ' .. status_class)

	:css('table-layout', 'fixed')

	:node(header_row)

	:tag('tr')

		:tag('td')

			:addClass('mbox-text wpb-main')

			:attr('colspan','2')

			:tag('table')

				for _, row in ipairs(rows) do

					banner_rows:node(row)

				end

if args.listas then

	frame:preprocess('{{DEFAULTSORT:' .. args.listas .. '}}')

end

local tstyle = frame:extensionTag ('templatestyles', '', {src='Module:Message box/tmbox.css'}) ..

	frame:extensionTag ('templatestyles', '', {src = 'Module:WikiProject banner' .. (sandbox or '') .. '/styles.css'})

return warning .. tstyle .. tostring(banner) .. categories_formatted, note_count, #taskforce_output, assessment_link

end



local parameter_check = function(frame, banner_name, project_name)

---------------------------

-- Unknown parameters -----

---------------------------

local parent_args = args_module.getArgs(frame, {parentOnly = true})

local parameters = {}

for parameter in banner_name:getContent():gmatch('{{{([^|}]+)') do

	table.insert(parameters, parameter)

end

parameters.preview = cfg.unknown_parameters.preview:format(wikilink(banner_name.fullText))

local unknown_category = cfg.unknown_parameters.tracking:format(project_name)

if not mw.title.new(unknown_category).exists then

	unknown_category = cfg.unknown_parameters.default

end

parameters.unknown = unknown_category and '[[' .. unknown_category .. '|_VALUE_]]' or ''

return require('Module:Check for unknown parameters')._check(parameters, parent_args)

end



local initialise = function(args, raw_args, inactive)

	args.demo_page = args_module.getArgs(frame, {parentOnly = true}).demo_page

	local project_name = args.PROJECT_NAME or 'WikiProject ' .. (args.PROJECT or 'PROJECT')

	local banner_name = mw.title.new(args.BANNER_NAME or 'Template:WikiProject ' .. (args.PROJECT or 'PROJECT'))

	local demo = not yesno(args.category or true, true) or args.demo_page

	local on_template_page = not demo and current_title.rootPageTitle==banner_name.rootPageTitle

	local unknown_parameters = banner_name.exists and not demo and parameter_check(frame, banner_name, project_name) or ''

	if on_template_page then

		local templatepage = require('Module:WikiProject banner/templatepage' .. (sandbox or '')).templatepage

		return templatepage(args, raw_args, inactive)

	else

		return unknown_parameters .. p._main(args, raw_args, demo or inactive, banner_name), nil -- nil to disregard subsequent returned values

	end

end



p.main = function(frame)

	local args = args_module.getArgs(frame, {frameOnly = true})

	local raw_args = args_module.getArgs(frame, {frameOnly = true, removeBlanks = false})

	return initialise(args, raw_args)

end



p.inactive = function(frame)

	local args = args_module.getArgs(frame, {frameOnly = true})

	local project_name = args.PROJECT_NAME or 'WikiProject ' .. (args.PROJECT or 'PROJECT')

	local project_link = mw.title.new(args.PROJECT_LINK or 'Wikipedia:' .. project_name)

	local _status = cfg.statusargs.PROJECT_STATUS or cfg.status.default_inactive

	local main_text = cfg.inactive.text:format(

		'_PAGETYPE_',

		project_link.prefixedText,

		project_name,

		_status

	)

	return initialise({

			PROJECT = args.PROJECT,

			PROJECT_STATUS = _status,

			BANNER_NAME = args.BANNER_NAME,

			IMAGE_LEFT = cfg.inactive.image,

			IMAGE_LEFT_SIZE = cfg.inactive.image_size,

			MAIN_TEXT = main_text,

			HOOK_NESTED_ASSESS = ' ' .. cfg.inactive.nested:format(_status),

			substcheck = args.substcheck,

			category = args.category

		},

		{

			class = frame.args.class,

			substcheck = '' -- to prevent warning on templatepage

		},

		true -- to prevent categorisation

	), nil

end



return p

Videos

Youtube | Vimeo | Bing

Websites

Google | Yahoo | Bing

Encyclopedia

Google | Yahoo | Bing

Facebook