وحدة:Proofreadpage index template

صفحة محمية جزئيًّا (سماح للمؤكدين تلقائيا)
من ويكي مصدر، المكتبة الحرة
--[=[
This is a module to implement logic for [[MediaWiki:Proofreadpage index template]]

It doesn't do everything yet, but over time it can accrete functions from
the template, which will become simpler and simpler until it's just an invoke.

Implemented so far:
 * Status categorisation and field
 * Some auxiliary data fields
]=]

local getArgs = require('Module:Arguments').getArgs
local messageBox = require('Module:Message box')
local ISO_639 = require('Module:ISO 639')

local p = {} --p stands for package

local DEFAULTS = {
	Source = '_empty_',
}


-- mapping of field ID to field properties
local headings = {
	['العنوان'] = {
		txt = 'العنوان',
	},
	['الحالة'] = {
		txt = 'الحالة',
	},
	oclc = {
		txt = 'OCLC',
	},
    transclusion = {
    	txt = 'التضمين',
    },
    ["Validation_date"] = {
    	txt = 'دُقق في',
    },
    ['المصدر'] = {
    	txt = 'المصدر'
    },
    ['المكان'] = {
    	txt = 'مكان النشر'
    },
    ['السنة'] = {
    	txt = 'سنة النشر'
    },
    ['الناشر'] = {
    	txt = 'الناشر'
    },
    ['المؤلف'] = {
    	txt = 'المؤلف'
    },
    ['المحرر'] = {
    	txt = 'المحرر'
    },
    ['المترجم'] = {
    	txt = 'المترجم'
    },
    ['الرسام'] = {
    	txt = 'الرسام'
    },
    doi = {
    	txt = 'DOI'
    },
    ['الأجزاء'] = {
    	txt = 'الأجزاء'
    }
}

local indicators = {
	pagegame = {
		name = "لعبة صفحات ويكي مصدر",
		image = "File:OOjs UI icon page number.svg",
		link = "{{fullurl:toolforge:ws-page-game|wikisource=en&index={{PAGENAMEE}}&lang=en}}",
		caption = "لعبة صفحات ويكي مصدر (صانع قوائم الصفحات خطوة بخطوة)"
	},
	purge = {
		name = "إفراغ الملف",
		image = "File:OOjs UI icon reload.svg",
		link = "{{fullurl:commons:File:{{PAGENAME}}|action=purge}}",
		caption = "إفراغ الملف"
	},
	book2scroll = {
		name = "book2scroll",
		image = "File:Library-logo-blue-outline.png",
		link = "{{fullurl:toolforge:book2scroll|lang=en&file={{PAGENAMEE}}}}",
		caption = "فتح في Book2Scroll"
	},
	bookreader = {
		name = "قارئ الكتب",
		image = "File:BookReader-favicon.svg",
		link = "{{fullurl:toolforge:bookreader/en/{{PAGENAMEE}}}}",
		caption = "فتح الملف في قارئ الكتب"
	},
}

local function get_heading(id)
	
	if headings[id] then
		return headings[id]['txt']
	end
	error( "غير قادر على إيجاد عنوان لـ: " .. id )
end

-- mapping from status code to category and status text
local index_status_data = {
	T = {
		cat = 'فهارس مدققة',
		txt = 'تم— كل صفحات العمل مدققة',
	},
	V = {
		cat = 'فهارس مصححة',
		txt = 'كل صفحات العمل مصححة، لكن بعضها غير مدقق',
	},
	C = {
		cat = 'فهارس غير مصححة',
		txt = 'يحتاج إلى تصحيح',
	},
	MS = {
		cat = 'فهارس-جاهزة للمطابقة والتقسيم',
		txt = "جاهز للمطابقة والفصل",
	},
	OCR = {
		cat = 'فهارس-بحاجة إلى طبقة نصية',
		txt = "الملف المصدر يحتاج إلى طبقة معرف ضوئي",
	},
	L = {
		cat = 'فهارس-الملف بحاجة إلى إصلاح',
		txt = 'الملف المصدر يحتاج إلى إصلاح قبل العمل عليه',
		error = true,
	},
	X = {
		cat = 'فهارس-الملف بحاجة إلى فحص',
		txt = 'يحتاج إلى قائمة صفحات (لفحص الملف ليكون جاهزا لاستخلاص النص)',
		error = true
	},
	_default = {
		cat = 'فهارس-حالة مجهولة',
		txt = 'حالة التدقيق مجهولة',
		error = true,
	}
}

-- construct a basic "field" row
local function construct_field(id, content)
	
	if id == nil or content == nil then
		return ''
	end
	
	local title = get_heading( id )

	local s = ''
	s = s .. mw.ustring.format('<tr id="ws-index-%s-row" class="ws-index-row">\n', id)
	s = s .. mw.ustring.format('<th id="ws-index-%s-label" class="ws-index-label" scope="row">%s</th>\n', id, title)
	s = s .. mw.ustring.format('<td id="ws-index-%s-value" class="ws-index-value">%s</td>\n', id, content)
	s = s .. '</tr>\n'

	return s
end

local function construct_link(url, text)
	return '[' .. url .. ' ' .. text .. ']'
end

local function int_link(target, text)
	return '[' .. '[' .. target .. (text and ('|' .. text)  or '') .. ']]'	
end

-- handy URL generators (remember to use mw.uri.encode on the bits you need to)
local url_gens = {
	oclc = function(id)
		return 'https://www.worldcat.org/oclc/' .. id	
	end,
	ark = function(id)
		return 'https://n2t.net/' .. mw.uri.encode(id)
	end,
	doi = function(id)
		return 'https://doi.org/' .. id
	end
}

-- construct a span which might be classed "error"
local function maybe_error_span(text, error) 
	local span = mw.html.create('span')
		:wikitext(text)
	if error then
		span:addClass('error')
	end
	return span
end


-- Construct the Title field (includes Vol. after Title if present)
local function construct_title_field(id, title, volume)
	local content = title
	if volume ~= nil and volume ~= "" then
		content = content .. "، ج" .. volume
	end
	
	return construct_field(id, content)
end

-- construct the source field:
-- - if a file exists, link it
-- - else just the text
local function construct_source_field(source)
	
	local value
	local file = mw.title.new( mw.title.getCurrentTitle().text, 'File' )

	if file.file.exists then
		value = int_link( ':' .. file.fullText, source )
	else
		value = source
	end

	local out = construct_field( 'المصدر', value )
	return out
end

local function construct_location_field( loc )
	return construct_field('المكان', loc)
end

-- construct the status (proofread/validated/...) field
local function construct_status_field(status)

	local out = ''
	local sd = index_status_data[status]
	
	if not sd then
		sd = index_status_data['_default']
	end
	
	out = out .. '[[تصنيف:' .. sd['cat'] .. ']]'

	local link_text = tostring(maybe_error_span(sd['txt'], sd['error']))
	local catlink = '[[:تصنيف:' .. sd['cat'] .. '|' .. link_text .. ']]'
	out = out .. construct_field("الحالة", catlink)

	return out
end

local transclusion_data = {
	yes = {
		cat = 'مضمن بالكامل',
		text = 'مضمن بالكامل',
		help = 'The work is fully transcluded, including front and end matter and images'
	},
	notimg = {
		cat = 'لم تضمن الصور كاملا',
		text = 'لم تضمن الصور كاملًا',
		help = 'The work is fully transcluded, but that some images are still missing or need improvement',
	},
	notadv = {
		cat = 'لم تضمن الإعلانات',
		text = 'لم تُضمن الإعلانات',
		help = 'The main body of the work is properly transcluded, though front- or end-matter advertising material is not'
	},
	held = {
		cat = 'التضمين معلق',
		text = 'التضمين معلق',
		help = 'There is a problem with transcluding the work (which should be explained on the talk page)'
	},
	check = {
		cat = 'بحاجة إلى فحص التضمين',
		text = 'بحاجة إلى فحص التضمين',
		help = ' The transclusion of the work is incomplete or needs checking'
	},
	no = {
		cat = 'فهرس غير مضمن',
		text = 'فهرس غير مضمن أو غير مراجع',
		help = ' This work is not transcluded or has not been reviewed for transclusion'
	}
}

local function construct_cat(cat)
	return "[[تصنيف:" .. cat .. "]]"	
end

-- construct the transclusion status
local function construct_transclusion_status(status, date)
	
	-- handle templates with no explicit status
	if status == nil then
		status = "no"
	end
	
	local td = transclusion_data[status]
	
	if td == nil then
		error("حالة الفهرس مجهولة: " .. status)
	end

	local catlink = '[[:تصنيف:' .. td['cat'] .. '|' .. td['text'] .. ']]'
	local out = construct_field("transclusion", catlink)
	out = out .. construct_cat( td['cat'])
	return out
end

local function construct_validated_date(date)
	local cat = 'فهارس دققت في ' .. date
	local indicator_text = 'دققت في ' .. date
	
	local out = '[[تصنيف:' .. cat .. ']]'
	
	local catlink = '[[:تصنيف:' .. cat .. '|' .. date .. ']]'
	out = out .. construct_field("Validation_date", catlink)
	
	out = out .. '<indicator name="validated-index-date">[[File:Yes Check Circle.svg|15px|link=تصنيف:' .. cat .. '|' .. indicator_text .. '|alt=صفحة فهرس مدقق.]]</indicator>'
	return out
end

local function getLanguageCat(l)
	-- get the name or nil
	local lang = ISO_639.language_name(l)
	
	if lang then
		return "صفحات فهارس لأعمال لغتها الأصلية " .. lang
	end
end

function p.fields(frame)
	
	local args = getArgs(frame)
	
	-- set any defaults
	for k, v in pairs( DEFAULTS ) do
		if args[ k ] == nil then
			args[ k ] = DEFAULTS[ k ]
		end
	end

	local s = ""

	s = s .. construct_title_field('العنوان', args['العنوان'], args['الجزء'])
	s = s .. construct_field('المؤلف', args['المؤلف'])
	s = s .. construct_field('المترجم', args['المترجم'])
	s = s .. construct_field('المحرر', args['المحرر'])
	s = s .. construct_field('الرسام', args['الرسام'])
	s = s .. construct_field('السنة', args['السنة'])
	s = s .. construct_field('الناشر', args['الناشر'])
	s = s .. construct_location_field(args['المكان'])
	s = s .. construct_source_field(args['المصدر'])
	
	s = s .. construct_status_field(args['الحالة'])
	
	-- always do this, even if the arg is not set
	s = s .. construct_transclusion_status(args["Transclusion"], args['Transclusion_date'])
	
	if args["Validation_date"] then
		s = s .. construct_validated_date(args["Validation_date"])	
	end

	if args["OCLC"] then
		local link = construct_link(url_gens['oclc'](args["OCLC"]), args['OCLC'])
		s = s .. construct_field("oclc", link)
	end
	
	if args["DOI"] then
		local link = construct_link(url_gens['doi'](args["DOI"]), args['DOI'])
		s = s .. construct_field("doi", link)
	end

	s = s .. construct_field('الأجزاء', args['الأجزاء'])

	-- language categorisations
	if args.Language then
		
		local langs = mw.text.split( args.Language, ',%s?', false)
		for _, lang in pairs(langs) do
			local cat = getLanguageCat(lang)
			if lang ~= 'ar' then
				if cat then
					s = s .. construct_cat(cat)
				else
					s = s .. construct_cat('صفحات فهارس لأعمال لغتها الأصلية مجهولة')
				end
			end
		end
		if #langs > 1 then
			s = s .. construct_cat('صفحات فهارس لأعمال متعددة اللغات الأصلية')
		end
	end

	return s
	
end

function p.talkremarks(frame)
	return _talkremarks(frame)
end

local function _talkremarks(frame)
	local talkTitle = mw.title.getCurrentTitle().talkPageTitle
	local talkText = talkTitle.prefixedText
	if talkTitle.exists then
		local notes = frame:callParserFunction("#lsth", talkText, "Quick notes")
		return frame:expandTemplate{
			title = "Index talk remarks",
			args = {
				notes = "\n" ..  notes
			}
		}
	end

	return ''
end


function p.indicators(frame)
	return _indicators(frame)
end

local function _indicators(frame)
	local s = ''
	for k, v in pairs(indicators) do
		local link = frame:preprocess(v.link)
		local img = mw.ustring.format("[[%s|20px|link=%s|%s]]", v.image, link, v.caption)
		s = s .. frame:extensionTag{
			name = "indicator",
			content = img,
			args = {
				name = v.name
			}
		}
	end
	return s
end


function p.cover(frame)
	local args = getArgs(frame)

	-- Workaround for pagelist preview that tries to parse this template
	-- without any context and with missing parameters via the API.
	if args['الصورة'] == nil then
		return ""
	end

	-- If Image param is not a (page) number then this is an image-based
	-- Index, so use the provided image as the cover image.
	if tonumber(args['الصورة']) == nil then
		local s = ""
		if mw.ustring.find(args['الصورة'], '^%[%[') ~= nil then
			-- It's a full image specification
			s = s .. args['الصورة']
		else
			-- Assume it's a filename with or without File: prefix
			local file = mw.ustring.gsub(args['الصورة'], "^[Ff]ile:", "")
			s = s .. "[[" .. "File:" .. file .. "|250px|class=ws-cover]]"
		end
		-- Add a tracking category
		s = s .. "[[" .. "تصنيف:فهارس لصور" .. "]]"
		return s
	end

	-- Otherwise it's a DjVu/PDF-backed index, in which case we fetch the
	-- cover image from a page in the (multipage) file.
	local indexTitle = mw.title.getCurrentTitle()
	local fileTitle = mw.title.makeTitle('File', indexTitle.text)
	if not fileTitle.file.exists then
		-- Our associated file doesn't exist so use a placeholder
		local s = "[[File:Placeholder book.svg|250px|link="
		s = s .. fileTitle.prefixedText .. "|class=ws-cover]]"
		s = s .. "[[" .. "تصنيف:فهارس لملفات مفقودة" .. "]]"
		return s
	end

	-- File exists and we have page number for the cover
	local s = "[[" .. fileTitle.prefixedText .. "|250px"
	s = s .. "|page=" .. tonumber(args['الصورة']) .. "|class=ws-cover]]"
	return s
end

function p.remarks(frame)
	local args = getArgs(frame)

	if args['الملاحظات'] ~= nil and args['الملاحظات'] ~= "" then
		return '<td id="ws-index-remarks">' .. args['الملاحظات'] .. '</td>'
	else
		return '<td id="ws-index-remarks-empty"></td>'
	end
end

function p.sortkey(frame)
	local args = getArgs(frame)

	local sortkey = ""

	if args['Key'] ~= nil and args['Key'] ~= "" then
		sortkey = args['Key']
	else
		sortkey = mw.title.getCurrentTitle().text
	end
	return frame:preprocess{text = "{{" .. "DEFAULTSORT:" .. sortkey .. "}}"} 
end


-- Wrapper to output .fields with containing html table element.
function p.metadata(frame)
	local metadatatable = mw.html.create("table")
	metadatatable:attr("id", "ws-index-metadata")
	local rows = p.fields(frame)
	metadatatable:node(rows)
	return tostring(metadatatable)
end


--
-- NEW EXPERIMENTAL CODE BELOW THIS LINE --
--

local cfg = mw.loadData("Module:Proofreadpage index template/config")

local CATS = {
	categories = {}
}
function CATS:addCat(cat)
	table.insert(self.categories, cat)
end
function CATS:getCats()
	local cats = ""
	for _, cat in ipairs(self.categories) do
		cats = cats .. "[[" .. "Category:" .. cat .. "]]"
	end
	return cats
end
function CATS:makeCatLink(cat, label)
	if label ~= nil and label ~= "" then
		return "[[:" .. "Category:" .. cat .. "|" .. label .. "]]"
	end
	return "[[:" .. "Category:" .. cat .. "]]"
end
function CATS:makeCat(cat, label)
	if label ~= nil and label ~= "" then
		return "[[" .. "Category:" .. cat .. "|" .. label .. "]]"
	end
	return "[[" .. "Category:" .. cat .. "]]"
end


-- construct a basic "field" row
local function __makeRow(id, content)
	if id == nil or id == "" or content == nil then
		return ''
	end

	local row = mw.html.create("tr")
	row
		:attr("id", "ws-index-" .. id .. "-row")
		:addClass("ws-index-row")
	:tag("th")
		:attr("scope", "row")
		:attr("id", "ws-index-" .. id .. "-label")
		:addClass("ws-index-label")
		:wikitext(cfg.headings[id].txt)
		:done()
	:tag("td")
		:attr("id", "ws-index-" .. id .. "-value")
		:addClass("ws-index-value")
		:wikitext(content)
	:allDone()

	return tostring(row)
end

-- Create indicator markup based on config
--
-- Loads the config module and creates indicator extension tags after pattern
--   <indicator name="foo">[[File:Foo.png|20px|link=bar]]</indcator>
-- The link is preprocessed as wikitext so it can contain parser functions etc.
local function __getIndicators(frame)
	local indicators = mw.loadData('Module:Proofreadpage index template/indicators')
	local s = ''
	for _, v in pairs(indicators) do
		local link = frame:preprocess(v.link)
		local img = mw.ustring.format("[[%s|20px|link=%s|%s]]", v.image, link, v.caption)
		s = s .. frame:extensionTag{
			name = "indicator",
			content = img,
			args = {
				name = v.name
			}
		}
	end
	return s
end

-- Get talk page notice if present
--
-- If the talk page associated with the current page exists, we use Labelled
-- Section Transclusion to transclude the section titled "Quick notes" and if
-- the result contains any text, return a message box with its contents.
local function __getTalkNotice(frame)
	local talkTitle = mw.title.getCurrentTitle().talkPageTitle
	local talkText = talkTitle.prefixedText
	if talkTitle.exists then
		local notes = frame:callParserFunction("#lsth", talkText, "Quick notes")

		local s = "Formatting guidelines specific to this work may have "
		s = s .. "already been established. Please check "
		s = s .. "[[" .. talkText .. "|the talk page]] for details."

		local box = messageBox.main("ombox", {
			type = "content",
		    text = s .. notes
		})
		return box
	end

	return ''
end

-- Get the image to use as the cover image for this index
--
-- If the Image parameter contains an integer it refers to a page in a DjVu/PDF
-- and can be used directly. Otherwise it may be a full image specification
-- that we can use directly, or just an image filename that we can construct
-- an image specification for.
local function __getCoverImage(args)
	local s = ""

	-- If Image param is not a (page) number then this is an image-based
	-- Index, so use the provided image as the cover image.
	if tonumber(args['الصورة']) == nil then
		if mw.ustring.find(args['الصورة'], '^%[%[') ~= nil then
			s = s .. args['الصورة'] -- It's a full image specification
		else
			-- Assume it's a filename with or without File: prefix
			local file = mw.ustring.gsub(args['Image'], "^[Ff]ile:", "")
			s = s .. "[[" .. "File:" .. file .. "|250px|class=ws-cover ws-index-cover]]"
		end
		-- Add a tracking category
		s = s .. CATS:makeCat("Image based indexes")
		return s
	end

	-- Otherwise it's a DjVu/PDF-backed index, in which case we fetch the
	-- cover image from a page in the (multipage) file.
	local indexTitle = mw.title.getCurrentTitle()
	local fileTitle = mw.title.makeTitle('File', indexTitle.text)
	if not fileTitle.file.exists then
		-- Our associated file doesn't exist so use a placeholder
		s = s .. "[[File:Placeholder book.svg|250px|link="
		s = s .. fileTitle.prefixedText .. "|class=ws-cover ws-index-cover]]"
		CATS:addCat("Indexes with missing files")
		return s
	end

	-- File exists and we have page number for the cover
	s = s .. "[[" .. fileTitle.prefixedText .. "|250px"
	s = s .. "|page=" .. tonumber(args['الصورة']) .. "|class=ws-cover ws-index-cover]]"
	return s
end

-- Get the pagelist provided by PRP
--
-- PRP furnished a finished rendered pagelist, so we just need to wrap it in a
-- suitable container, add a legend, etc.
local function __getPagelist(args)
	-- Main container
	local plcontainer = mw.html.create("div")
	plcontainer
		:addClass("ws-index-pagelist-container")
		:addClass("mw-collapsible") -- make it collapsible
	:tag("div") -- The heading/legend
		:addClass("ws-index-pagelist-heading")
		:wikitext("الصفحات")
		:wikitext(" ") -- Force a space between heading and legend.
		:tag("span")
			:addClass("ws-index-pagelist-heading-legend")
			:wikitext("(مفتاح إلى [[مساعدة:حالة الصفحة|حالة الصفحة]])")
			:done()
		:done()
	:tag("div") -- The pagelist itself
		:addClass("ws-index-pagelist")
		:addClass("index-pagelist") -- legacy support
		:addClass("mw-collapsible-content") -- make it collapsible
		:wikitext(args["الصفحات"])

	return tostring(plcontainer)
end


-- Get the metadata fields.
local function __getMetadata(frame, args)
	-- set any defaults
	for key, _ in pairs(cfg.defaults) do
		if args[key] == nil then
			args[key] = cfg.defaults[key]
		end
	end

	local s = ""

	-- Construct the Title field (includes Vol. after Title if present)
	local title = args['Title']
	if args['Volume'] ~= nil and args['Volume'] ~= "" then
		title =  title .. ", " .. args['Volume']
	end
	s = s .. __makeRow('title', title)

	s = s .. __makeRow('author',      args['Author'])
	s = s .. __makeRow('translator',  args['Translator'])
	s = s .. __makeRow('editor',      args['Editor'])
	s = s .. __makeRow('illustrator', args['Illustrator'])
	s = s .. __makeRow('year',        args['Year'])
	s = s .. __makeRow('publisher',   args['Publisher'])
	s = s .. __makeRow('place',       args['Address'])

	local location = args["Source"]
	local file = mw.title.new(mw.title.getCurrentTitle().text, 'File')
	if file.exists then
		location = "[[:" .. file.fullText .. "|" .. args["Source"] .. "]]"
	end
	s = s .. __makeRow('source', location)


	local status = cfg.status[args['Progress']] or cfg.status['_default']
	CATS:addCat(status.cat) -- Add this index to that cat
	local linktext = mw.html.create('span'):wikitext(status.txt)
	if status.error then
		linktext:addClass('error')
	end
	local statuslink = CATS:makeCatLink(status.cat, tostring(linktext))
	s = s .. __makeRow('progress', statuslink)


	local transclusion = cfg.transclusion[args["Transclusion"] or "no"] -- always do this, even if the arg is not set
	CATS:addCat(transclusion.cat)
	local transclusionlink = CATS:makeCatLink(transclusion.cat, transclusion.txt)
	s = s .. __makeRow("transclusion", transclusionlink)


	if args["Validation_date"] then
		local valcat = 'Indexes validated in ' .. args["Validation_date"]
		local valtxt = 'Validated in ' .. args["Validation_date"]
		CATS:addCat(valcat)
		local valcatlink = CATS:makeCatLink(valcat, args["Validation_date"])
		s = s .. __makeRow("validation_date", valcatlink)
		s = s .. frame:extensionTag{ -- FIXME: need the frame here!
			name = "indicator",
			content = '[[File:Yes Check Circle.svg|15px|link=Category:' .. valcat .. '|' .. valtxt .. '|alt=Validated index page.]]',
			args = {
				name = "validated-index-date"
			}
		}
	end

	if args["OCLC"] then
		local link = construct_link(url_gens['oclc'](args["OCLC"]), args['OCLC'])
		s = s .. __makeRow("oclc", link)
	end
	
	if args["DOI"] then
		local link = construct_link(url_gens['doi'](args["DOI"]), args['DOI'])
		s = s .. __makeRow("doi", link)
	end

	s = s .. __makeRow('volumes', args['Volumes'])

	-- language categorisations
	if args["Language"] then
		local langs = mw.text.split(args["Language"], ',%s?', false)
		for _, lang in pairs(langs) do
			local langcat = "Index الصفحات of works originally in "
			langcat = langcat .. ISO_639.language_name(lang) or "an unknown language"
			CATS:addCat(langcat)
		end
		
		if #langs > 1 then
			CATS:addCat('Index pages of works originally in multiple languages')
		end
	end

	local metadatatable = mw.html.create("table")
		:addClass("ws-index-metadata")
		:wikitext(s)
	return tostring(metadatatable)
end


local function __main(frame)
	local args = getArgs(frame)

	local s = "" -- Where we collect all the bits and bobs to return

	-- The overall html structure in which each component is inserted
	local indexcontainer = mw.html.create("div")
		:addClass("ws-index-container")
	if tonumber(args["tmplver"]) == 42 then
		indexcontainer:addClass("ws-tng") -- Tag for "TNG" mode i asked for.
	end

	-- Get the indicators (NB! Needs access to the frame!)
	s = s .. __getIndicators(frame)

	-- Get talk page notice if present (NB! Needs access to the frame!)
	s = s .. __getTalkNotice(frame)

	-- Get the image to use as the cover image for this index
	local cover = __getCoverImage(args)
	indexcontainer:tag("div")
		:addClass("ws-index-cover-container")
		:wikitext(cover)

	-- Get metadata table (NB! Needs access to the frame!)
	local metadata = __getMetadata(frame, args)
	indexcontainer:tag("div")
		:addClass("ws-index-metadata-container")
		:wikitext(metadata)

	-- Get the pagelist for the index
	local pagelist = __getPagelist(args)
	indexcontainer:wikitext(pagelist)

	-- Add the remarks field (toc)
	local remarks = indexcontainer:tag("div")
		:addClass("ws-index-remarks-container")
	if args['الملاحظات'] == nil or args['الملاحظات'] == "" then
		remarks:addClass("ws-index-remarks-empty")
	end
	remarks:wikitext(args['الملاحظات'])

	-- Return the HTML structure and the accumulated categories.
	return tostring(indexcontainer) .. CATS:getCats()
end


function p.main(frame)
	local args = getArgs(frame)

	local s = "" -- Where we collect all the bits and bobs to return

	if args["tmplver"] ~= nil and args["tmplver"] ~= "" then
		return __main(frame)
	end

	-- First, the talk remarks notes (nb! needs frame object!)
	s = s .. _talkremarks(frame)

	-- Then the indicators (nb! needs frame object!)
	s = s .. _indicators(frame)

	-- Construct the table
	local outertable = mw.html.create("table")
	outertable:attr("id", "ws-index-container")
	local outertr = outertable:tag("tr")

	local maincell = outertr:tag("td")
	maincell:attr("id", "ws-index-main-cell")

	local maintable = maincell:tag("table")
	maintable:attr("id", "ws-index-main-table")
	local firstrow = maintable:tag("tr")
	local maincell = firstrow:tag("td")
	local coverdiv = maincell:tag("div")
	coverdiv:attr("id", "ws-index-cover-container")
	coverdiv:wikitext(p.cover(frame))
	maincell:wikitext(p.metadata(frame))
	local secondrow = maintable:tag("tr")
	local plcell = secondrow:tag("td")
	local pldiv = plcell:tag("div")
	pldiv:attr("id", "ws-index-pagelist-container")
	pldiv:addClass("mw-collapsible")
	pldiv:wikitext('<em>الصفحات</em> <span id="ws-index-pagelist-legend">(مفتاح إلى [[مساعدة:حالة الصفحة{{!}}حالة الصفحة]])</span>')
	local plinner = pldiv:tag("div")
	plinner:attr("id", "ws-index-pagelist")
	plinner:addClass("index-pagelist mw-collapsible-content")
	plinner:wikitext(args['الصفحات'])

	outertr:wikitext(p.remarks(frame))

	s = s .. tostring(outertable)

	s = s .. p.sortkey(frame)

	return s
end

return p