Module:Protection banner

From Chalo Chatu, Zambia online encyclopedia
Jump to navigationJump to search

This page documents the Chalo Chatu–only protection banner module. It provides a lightweight, dependency-free implementation for protection notices and padlock indicators. It is declarative: pages call the module (usually via Template:PP-meta) and pass action, level, reason, and dates. The module does not query actual MediaWiki protection state.

Overview

  • Designed for Chalo Chatu only
  • No external dependencies or WMF modules
  • Outputs either a full banner or a small padlock
  • Adds simple, predictable protection categories
  • Icons and category names configurable in Module:Protection banner/config

How it works

Most pages should not call the module directly. Use the wrapper template:

  • Template:PP-meta invokes the module with your parameters
  • Module:Protection banner renders the banner/padlock and adds categories

Quick start (recommended wrapper)

Place this in the article or template needing a notice:

{{pp-meta|vandalism|action=edit|level=autoconfirmed|expiry=indef|date=2025-09-29}}

Small padlock indicator:

{{pp-meta|dispute|action=edit|level=sysop|small=yes|link=Chalo Chatu:Protection policy}}

Parameters (via Template:PP-meta)

All parameters are passed through to the module.

1 or reason
Free-text reason shown in the banner line. Example: vandalism, dispute, sock.
action
edit (default), move, upload.
level
sysop, templateeditor, extendedconfirmed, autoconfirmed, * (unprotected). Determines icon, wording, and category.
expiry
indef for indefinite; or free text such as 2026-12-31. Shown as provided.
date
Free text such as 2025-09-29. Shown as Protected on 2025-09-29.
small
yes to output a small padlock indicator instead of a full banner.
category
yes (default) to add a protection category; no to suppress.
image
Optional file name override for the padlock icon. Example: Padlock-custom.svg
link
Optional page to link the padlock to when small=yes. Example: Chalo Chatu:Protection policy
pagetype
Defaults to page. Used in phrasing (This page is semi-protected...). You may set article, template, module, etc.

Levels and default wording

The module maps levels to human-readable phrases.

edit/sysop
fully protected
edit/templateeditor
template-protected
edit/extendedconfirmed
extended confirmed protected
edit/autoconfirmed
semi-protected
*
unprotected

Move and upload actions use simple default wording (move-protected, upload-protected).

Categories

When category=yes and level is not *, the module adds one category based on action/level. Defaults are set in Module:Protection banner/config:

  • Fully protected pages
  • Template-protected pages
  • Extended-confirmed protected pages
  • Semi-protected pages
  • Move-protected pages
  • Upload-protected pages
  • Protected pages (fallback)

Rename or localize categories by editing Module:Protection banner/config.

Icons

Icons are file names stored in Module:Protection banner/config. Replace with your local files as needed:

  • Padlock-red.svg, Padlock-orange.svg, Padlock-amber.svg, Padlock-yellow.svg, Padlock-blue.svg, Padlock-grey.svg

You can override per-call with image=.

Examples

Full banner, indefinite semi-protection for vandalism:

{{pp-meta|vandalism|action=edit|level=autoconfirmed|expiry=indef|date=2025-09-29}}

Full banner, extended-confirmed protection with expiry:

{{pp-meta|dispute|action=edit|level=extendedconfirmed|expiry=2026-06-30}}

Small padlock on a template:

{{pp-meta|reason=high-risk template|action=edit|level=templateeditor|small=yes|link=Chalo Chatu:Template protection}}

Suppress category (maintenance only):

{{pp-meta|reason=test|action=edit|level=autoconfirmed|category=no}}

Daughter templates (optional)

You may create simple wrappers that prefill parameters, for example:

Template:PP-vandalism

<includeonly>{{pp-meta|vandalism|action={{{
action|edit}}}|level={{{level|autoconfirmed}}}|expiry={{{expiry|indef}}}|small={{{small|}}}|date={{{date|}}}}}</includeonly>
<noinclude>Wrapper for vandalism protection. [[Category:Protection templates]]</noinclude>

Template:PP-dispute

<includeonly>{{pp-meta|dispute|action={{{
action|edit}}}|level={{{level|extendedconfirmed}}}|expiry={{{expiry|}}}|small={{{small|}}}|date={{{date|}}}}}</includeonly>
<noinclude>Wrapper for dispute-driven protection. [[Category:Protection templates]]</noinclude>

Configuration

Site-wide configuration lives in Module:Protection banner/config:

  • images: per-action, per-level icon filenames
  • protectionLevels: phrases used in banner text
  • categories: mapping from action/level to category names

Update that file to adjust look, wording, and categories globally.

Limitations

  • Declarative only; does not read MediaWiki protection state
  • Age and date strings are displayed as provided; no automatic date parsing
  • Minimal CSS. For consistent styling, add optional CSS in MediaWiki:Common.css for .cc-mbox and .cc-padlock

See also


-- Module:Protection banner (Chalo Chatu)
-- Lightweight, dependency-free. Declarative protection only.
-- Implements {{pp-meta}}-style usage via p.main().
-- Params (typical):
--   action=edit/move/upload
--   level=autoconfirmed/extendedconfirmed/templateeditor/sysop/* (unprotected)
--   reason=vandalism/dispute/sock/etc (free text)
--   expiry=indef | YYYY-MM-DD | free text (shown as-is)
--   date=YYYY-MM-DD (shown as "Protected on …")
--   small=yes -> padlock indicator; else banner
--   category=yes/no (default yes)
--   section=anchor on talk link (optional)
--   image=File name override (optional)
--   link=target page for padlock click (optional)

local p = {}

-- Basic yes/no parser
local function yesno(v, default)
  if v == nil then return default end
  if type(v) == 'boolean' then return v end
  local s = tostring(v):lower()
  if s == 'yes' or s == 'y' or s == 'true' or s == '1' then return true end
  if s == 'no'  or s == 'n' or s == 'false' or s == '0' then return false end
  return default
end

-- HTML builder helpers (simple, safe)
local function esc(s)
  s = tostring(s or '')
  return s:gsub('&','&amp;'):gsub('<','&lt;'):gsub('>','&gt;')
end

local function tag(name, attrs, content)
  local a = {}
  if attrs then
    for k,v in pairs(attrs) do
      if v ~= nil and v ~= '' then
        table.insert(a, string.format(' %s="%s"', k, esc(v)))
      end
    end
  end
  if content == nil then
    return string.format('<%s%s />', name, table.concat(a))
  end
  return string.format('<%s%s>%s</%s>', name, table.concat(a), content, name)
end

-- Minimal styling (relies on site Common.css, but works standalone)
local function messageBox(imageHtml, textHtml)
  local left = tag('div', {style='flex:0 0 auto; padding-right:8px;'}, imageHtml or '')
  local right = tag('div', {style='flex:1 1 auto;'}, textHtml or '')
  local row = tag('div', {style='display:flex; align-items:flex-start;'}, left .. right)
  return tag('div', {
    class='cc-mbox cc-mbox-protection',
    style='border:1px solid #aaa;background:#f9f9f9;padding:8px;margin:0 0 1em 0;'
  }, row)
end

local function padlockIndicator(imageHtml, linkTarget, alt)
  local content = imageHtml or ''
  if linkTarget and linkTarget ~= '' then
    content = string.format('[[%s|%s]]', linkTarget, content)
  end
  return tag('span', {class='cc-padlock', title=alt or 'Page is protected'}, content)
end

local function fileLink(filename, size, alt, link)
  if not filename or filename == '' then return '' end
  local core = string.format('[[File:%s|%s|%s]]',
    filename,
    size or '20px',
    (alt and ('alt='..alt)) or ''
  )
  if link and link ~= '' then
    return string.format('[[%s|%s]]', link, core)
  end
  return core
end

-- Default config (overrideable by Module:Protection banner/config if present)
local function getConfig()
  local ok, cfg = pcall(require, 'Module:Protection banner/config')
  if ok and type(cfg) == 'table' then return cfg end
  -- Built-in defaults for Chalo Chatu
  return {
    images = {
      edit = {
        sysop = 'Padlock-red.svg',
        templateeditor = 'Padlock-orange.svg',
        extendedconfirmed = 'Padlock-amber.svg',
        autoconfirmed = 'Padlock-yellow.svg',
        ['*'] = 'Padlock-grey.svg',
        default = 'Padlock-blue.svg'
      },
      move = { default = 'Padlock-blue.svg' },
      upload = { default = 'Padlock-blue.svg' },
      default = 'Padlock-blue.svg'
    },
    padlockIndicatorName = 'pp',
    -- Simple phrasing tables
    protectionLevels = {
      edit = {
        sysop='fully protected', templateeditor='template-protected',
        extendedconfirmed='extended confirmed protected',
        autoconfirmed='semi-protected', ['*']='unprotected', default='protected'
      },
      move = { default='move-protected' },
      upload = { default='upload-protected' }
    },
    categories = {
      -- Built from: action/level -> category name. Fallbacks used below.
      ['edit/sysop'] = 'Fully protected pages',
      ['edit/autoconfirmed'] = 'Semi-protected pages',
      ['edit/extendedconfirmed'] = 'Extended-confirmed protected pages',
      ['edit/templateeditor'] = 'Template-protected pages',
      ['move/sysop'] = 'Move-protected pages',
      ['upload/sysop'] = 'Upload-protected pages',
      default = 'Protected pages'
    },
    talkNsName = 'Talk'
  }
end

local function pickImage(cfg, action, level, override)
  if override and override ~= '' then return override end
  local imgs = cfg.images
  if imgs[action] then
    return imgs[action][level] or imgs[action].default or imgs.default
  end
  return imgs.default
end

local function pickLevelName(cfg, action, level)
  local t = cfg.protectionLevels[action] or {}
  return t[level] or t.default or 'protected'
end

local function buildCategory(cfg, action, level)
  local key = (action or 'edit') .. '/' .. (level or '*')
  local cat = cfg.categories[key] or cfg.categories.default
  return string.format('[[Category:%s]]', cat)
end

local function buildText(action, levelName, reason, expiry, date, pagetype)
  local parts = {}
  local ptype = pagetype or 'page'
  table.insert(parts, string.format("This %s is %s", ptype, levelName))
  if reason and reason ~= '' then
    table.insert(parts, string.format(" for %s", reason))
  end
  table.insert(parts, '.')
  if expiry and expiry ~= '' and expiry ~= 'indef' then
    table.insert(parts, string.format(" Protection expires: %s.", expiry))
  elseif expiry == 'indef' then
    table.insert(parts, " Protection is indefinite.")
  end
  if date and date ~= '' then
    table.insert(parts, string.format(" Protected on %s.", date))
  end
  return table.concat(parts)
end

-- Minimal args fetcher (works for template or module invocation)
local function getArgs(frame)
  local parent = frame:getParent()
  local src = parent or frame
  local args = {}
  for k,v in pairs(src.args) do
    if v ~= '' then args[k] = v end
  end
  return args
end

local function render(args, cfg)
  local action = (args.action or 'edit'):lower()
  local level  = (args.level or '*'):lower()
  local reason = args[1] or args.reason
  local expiry = args.expiry
  local date   = args.date
  local small  = yesno(args.small, false)
  local putCat = yesno(args.category, true)
  local image  = pickImage(cfg, action, level, args.image)
  local link   = args.link
  local alt    = pickLevelName(cfg, action, level)
  local padImg = fileLink(image, small and '20px' or '40px', alt, small and link or nil)

  local out = {}

  if small then
    table.insert(out, padlockIndicator(padImg, link, alt))
  else
    local text = buildText(action, alt, reason, expiry, date, args.pagetype)
    local head = tag('div', {style='font-weight:bold;margin-bottom:2px;'}, esc(alt:gsub("^%l", string.upper)))
    local body = tag('div', nil, esc(text))
    table.insert(out, messageBox(padImg, head .. body))
  end

  if putCat and level ~= '*' then
    table.insert(out, buildCategory(cfg, action, level))
  end

  return table.concat(out)
end

function p.main(frame)
  local cfg = getConfig()
  local args = getArgs(frame)
  return render(args, cfg)
end

-- For module testing:
function p._render(targs, tcfg) return render(targs or {}, tcfg or getConfig()) end

return p