require('strict')local p = local sandbox = '/sandbox'local cfg = mw.loadData('Module:WikiProject banner/config' .. (sandbox or ))local auxiliary = cfg.auxiliary_module .. (sandbox or )local args_module = require('Module:Arguments')local mbox = require('Module:Message box').mainlocal yesno = require('Module:Yesno')local frame = mw.getCurrentFramelocal lang = mw.getLanguage(cfg.language)local current_title = mw.title.getCurrentTitlelocal parameter_format = function(parameter, value) return frame:expandTemplateend
local wikilink = function(link, display) if link then return display and ''..display..'' or ''..link..'' else return display or endendlocal display_error = function(text) local span = mw.html.create('div') :addClass('error') :wikitext(text) return tostring(span) end
local image = function(image_name, size, alt, position) return image_name and ''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 endend
local isarticle = function(class) local article = true for _,v in ipairs(cfg.quality.non_article_classes) do if class
----------------------------- Importance mask -----------------------------------local importance_mask = function(raw_importance, class, scale, banner_name) local importance if 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) end else importance = frame:expandTemplate end if importance
----------------------------- 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').getParameter local success, result = get_parameter_value(page, cfg.banner_shell.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 parameterendp.class_mask = function(class, title, FQS, pagetype) local resolveFQSgrade = function(class) return FQS and lang:ucfirst(class) or 'NA' end local out title = title or mw.title.getCurrentTitle local ns = title.namespace class = class:match('^%s*(.-)%s*$'):lower
if pagetype
'soft redirect' then out = resolveFQSgrade('redirect') elseif pagetype
'article' then if class
'stub' then -- Ucfirst out = lang:ucfirst(class) elseif class
'c' or class
'fl' or class
'ga' then -- Upper-case out = class:upper elseif class
'sia' or class
'sl' then-- List out = 'List' else out = -- unassessed end elseif ns
711 then -- File talk if class
local page_assessment = function(project, class, importance) -- add PageAssessments parser function local assessment = table.concat('|') frame:preprocess('')end
local bubble = function(text, colour, conflict) local out = mw.html.create('span') :addClass('wpb-header-bubbles') :css('background', colour) :css('border', conflict and cfg.banner_shell.conflict.border or (cfg.quality.border..' '..colour)) :wikitext(text) return tostring(out)end
p._main = function(args, raw_args, demo, banner_name, inactive)----------------------------- Initialise parameters -----------------------------local project = args.PROJECT or 'PROJECT'local project_name = args.PROJECT_NAME or 'WikiProject ' .. projectlocal 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 ))._mainlocal rows, nested_ratings, task_forces, notes, categories, taskforce_categories =,,,,, local add_category = function(category, key) if category and category~='none' then table.insert(categories,) endendlocal parse_text = function(text) return text and text:gsub('_PAGETYPE_', pagetype)endfor 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_categories[tf] then -- initialise table taskforce_categories[tf] = end table.insert(taskforce_categories[tf], cat) end endendtable.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 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',) if not current_title.subjectPageTitle:inNamespace(2) then add_category(cfg.namespace_warning.categories, sortkey) endend----------------------------- Substitution warning ------------------------------if args.substcheck
{{'..banner_name.prefixedText..'}}
' ) warning = warning .. mbox('ombox',) .. cfg.subst_warning.categoriesend----------------------------- 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 return cellendlocal portal = args.PORTALlocal portal_box = portal and frame:expandTemplate 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_sizelocal metadata = function(class, data) return mw.html.create('span'):addClass(class):wikitext(data)endlocal text_cell = mw.html.create('td') :addClass('mbox-text') :wikitext(main_text) :tag('span'):addClass('metadata wpb-metadata') :node(metadata('wpb-project', project)) :node(metadata('wpb-project_link', project_link.prefixedText)) :node(metadata('wpb-banner_name', banner_name.prefixedText)) :node(metadata('wpb-assessment_cat', assessment_cat)) :donelocal primary_row = mw.html.create('tr') :node(primary_image(args.IMAGE_LEFT, image_left_size)) :node(text_cell) :node(primary_image(args.IMAGE_RIGHT, args.IMAGE_RIGHT_SIZE or cfg.image.default_size))table.insert(rows, primary_row)----------------------------- Quality assessment --------------------------------local assessment_link = args.ASSESSMENT_LINKif not assessment_link then local fallback = mw.title.new(project_link.prefixedText .. '/Assessment') assessment_link = fallback.exists and fallback.prefixedTextelseif assessment_link'no' then assessment_link = nilendlocal 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 endendlocal class = raw_args.classlocal title = args.demo_page and mw.title.new(args.demo_page) or current_titlelocal article_class = p.readarticleclass(title.prefixedText)if not article_class then if pagetype
3 then --User talk namespace for _, user in ipairs(cfg.banner_shell.valid_users) do if string.find(title.rootText, user) then add_category(cfg.banner_shell.category.no_banner_shell) end end else add_category(cfg.banner_shell.category.no_banner_shell) endendif class then -- banner gives quality ratings article_class = article_class and p.class_mask(article_class, title, false, pagetype) local show_quality, conflict = true, false if args.QUALITY_CRITERIA
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_table[arg] = val end new_arg_table.class = article_class -- replace class with inherited class local article_class_normalised = mw.text.trim(frame:expandTemplate) 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 -- local class also does not exist, check whether any other class parameters are defined inside the shell local classparam = p.readarticleclass(title.prefixedText) if classparam
or 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.banner_shell.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
'article' then rating = class
'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.banner_shell.conflict.text or cfg.quality.rating:format(pagetype, rating, scale) local colour = cfg.quality.colour[class] 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 'Unassessed' or (class..'‑class'), colour, conflict) ) end add_category(category)endif args.HOOK_ASSESS then table.insert(rows, args.HOOK_ASSESS)endif 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(auxiliary).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 '???' or importance)) :done :tag('td') :addClass('mbox-text') :attr('colspan', '2') :wikitext(importance_rating) :done 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)endpage_assessment(project, class, importance)if args.HOOK_IMPORTANCE then table.insert(rows, args.HOOK_IMPORTANCE)endif args.QII_FORMAT then add_category(require(auxiliary).quality_importance_insection(args, class, importance, importance_name))end----------------------------- Collapsing sections -------------------------------local collapse_section = function(collapse, new_rows, header) if collapse then local header_row = mw.html.create('tr') :tag('th') :attr('colspan','3') :addClass('wpb-collapsed-head') :wikitext(header) :done local blank_row = mw.html.create('tr') :tag('td') :addClass('mbox-image wpb-gutter') :css('min-width', image_left_size) :tag('span') :addClass('wpb-iefix') :wikitext('/ ') :done --TO FIX IE :done :tag('td'):done :tag('td'):done local collapsed_rows = mw.html.create('table') :addClass('mw-collapsible mw-collapsed') :node(header_row) :node(blank_row) for _, row in ipairs(new_rows) do collapsed_rows:node(row) end local collapsed_section = mw.html.create('tr') :tag('td') :attr('colspan','3') :addClass('wpb-collapsed-notes') :node(collapsed_rows) :done table.insert(rows, collapsed_section) else for _, row in ipairs(new_rows) do table.insert(rows, row) end endend----------------------------- Task forces ---------------------------------------local nested_tf, taskforce_output =, local tf_default_size = args.TF_SIZE or cfg.task_force.default_sizefor _, k in ipairs(task_forces) do local tf_prefix = 'TF_' .. k .. '_' local tf_assessment_cat = args[tf_prefix..'ASSESSMENT_CAT'] or (args[tf_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
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 args[tf_prefix..'QII_FORMAT'] then add_category(require(auxiliary).quality_importance_insection(args, class, tf_importance, importance_name, tf_prefix)) end if args[tf_prefix..'NAME'] then page_assessment(project..'/'..args[tf_prefix..'NAME'], class, tf_importance) end if args[tf_prefix..'MAIN_CAT'] then add_category(args[tf_prefix..'MAIN_CAT']) end if args[tf_prefix..'NESTED'] then table.insert(nested_tf, wikilink(args[tf_prefix..'LINK'], args[tf_prefix..'NESTED'])) end for _, c in ipairs(taskforce_categories[k] or) do-- add additional taskforce categories add_category(args[tf_prefix..'CAT_'..c]) endendif args.HOOK_TF then table.insert(taskforce_output, args.HOOK_TF)endlocal threshold = tonumber(args.TF_COLLAPSE) or (args.TF_HEADER and cfg.task_force.lower_threshold) or cfg.task_force.upper_thresholdcollapse_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_sizelocal 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) :done table.insert(note_output, new_note) if note_image then local icon = mw.html.create('span') :addClass('wpb-header-bubbles') :wikitext('') table.insert(nested_ratings, tostring(icon)) end endendlocal auto = falselocal auto_arg = args.auto and args.auto:lowerif (auto_arg
'stub') and class
'inherit' or auto_arg
'stub' then sort_prefix = 'S' elseif auto
'inherit' then local sort_codes = cfg.auto.sort_codes sort_prefix = sort_codes[class] or cfg.auto.default_sort_code end render_noteendif yesno(args.attention, true) then local attention_cat = args.ATTENTION_CAT or cfg.attention.default_cat:format(project) render_noteendif yesno(args.infobox, true) then local infobox_cat = args.INFOBOX_CAT or cfg.infobox.default_cat:format(project) render_noteendfor _, k in ipairs(notes) do local note_prefix = 'NOTE_' .. k .. '_' render_noteendif yesno(args['image-needed'], true) then local image_needed_args = require(auxiliary).image_needed(args, pagetype) render_note(image_needed_args)endif yesno(args['collaboration-candidate'], true) or yesno(args['collaboration-current'], true) or yesno(args['collaboration-past'], true) then local collaboration_args = require(auxiliary).collaboration(args, pagetype, current_title) render_note(collaboration_args.candidate) render_note(collaboration_args.current) render_note(collaboration_args.past)endif yesno(args['a class'], true) then local a_class_args = require(auxiliary).a_class(args, lang) render_note(a_class_args)endif yesno(args['peer review'], true) or yesno(args['old peer review'], true) then local peer_review_args = require(auxiliary).peer_review(args, current_title) render_note(peer_review_args.current) render_note(peer_review_args.past)end
local note_count = #note_outputif 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
local parameter_check = function(frame, banner_name, project_name)----------------------------- Unknown parameters --------------------------------local parent_args = args_module.getArgs(frame,)local parameters = for parameter in banner_name:getContent:gmatch('