🇮🇷 Iran Proxy | https://www.wikipedia.org/wiki/Module:Archives
Jump to content

Module:Archives

From Wikipedia, the free encyclopedia

local p = {}
local cfg = mw.loadData('Module:Archives/config')
local mbots = require('Module:Archives/bots/sandbox')

local function is_filled(var)
	return var and var ~= ''
end

-- simple helper for simple cases
local function var_or_default(var, default)
	if is_filled(var) then
		return var
	else
		return default
	end
end

local function wikilink(link, display)
	if display then
		return '[[' .. link .. '|' .. display .. ']]'
	else
		return '[[' .. link .. ']]'
	end
end

local function talk_other(demospace, talk)
	if is_filled(demospace) then return demospace end
	
	if mw.title.getCurrentTitle().isTalkPage then return talk end
	
	return nil -- just return nil rather than 'other' since we have no need
end

local function add_image(image)
	return mw.html.create('div'):addClass('archives-image'):wikitext(
		require('Module:Sandbox/Izno/InfoboxImage')._InfoboxImage({
			[cfg.img_mod.image] = var_or_default(image.image, cfg.image),
			[cfg.img_mod.alt] = var_or_default(image.alt, cfg.img_mod.alt_none),
			[cfg.img_mod.link] = var_or_default(image.link, cfg.img_mod.link_none),
			[cfg.img_mod.size] = var_or_default(image.size, nil),
			[cfg.img_mod.sizedefault] = cfg.image_size
		})
	)
end

local function search_box(frame, is_banner, root, search)

	if search.search and search.search == cfg.search_no then return nil end
	
	local prefix = ''
	if is_filled(search.prefix) then
		prefix = search.prefix
	-- this double-check elseif may move out to code-proper
	elseif is_filled(root) then
		prefix = root
	else
		prefix = mw.title.getCurrentTitle().prefixedText .. '/'
	end
	
	local sbreak
	if search.sbreak and (search.sbreak == 'yes' or search.sbreak == 'no') then
		sbreak = search.sbreak
	end
	if not sbreak then
		if is_banner then
			sbreak = 'no'
		else
			sbreak = 'yes'
		end
	end
	
	local width = ''
	if not is_banner then
		width = var_or_default(search.width, cfg.search_width)
	end
	
	local label = var_or_default(search.label, cfg.search_label)
	
	local placeholder = var_or_default(search.placeholder, cfg.search_placeholder)
	
	local inputbox_options = {
		['bgcolor'] = 'transparent',
		['type'] = 'fulltext',
		['prefix'] = prefix,
		['break'] = sbreak,
		['width'] = width,
		['searchbuttonlabel'] = label,
		['placeholder'] = placeholder
	}
	
	local inputbox_content = {}
	for k, v in pairs(inputbox_options) do
		table.insert(inputbox_content, k .. '=' .. v)
	end

	return mw.html.create('div'):addClass('archives-search'):wikitext(frame:extensionTag{
		name = 'inputbox',
		content = table.concat(inputbox_content, '\n')
	})
end

local function note_auto(frame, auto)
	
	local bot_disabled = var_or_default(auto.nobot, false)
	if bot_disabled then return nil end
	
	-- TODO: autodetection makes this line wrong
	if not is_filled(auto.age) and not is_filled(auto.target) then return nil end
	
	local age = var_or_default(auto.age, nil)
	local target = var_or_default(auto.target, nil)
	
	local target_text = ''
	if target then
		target_text = mw.ustring.format(
			cfg.has_archives,
			frame:callParserFunction( '#rel2abs', target ),
			age and ' ' or ''
		)
	end
	local age_text = ''
	if age then
		local units = var_or_default(auto.units, cfg.units)
		-- there's probably a friendlier l10n way to do this check on units...
		-- TODO make it friendlier. maybe split it to a separate function?
		-- (borrowed from Module:String.endswith in the meantime)
		if age ~= '1' and mw.ustring.sub(units, -1, -1) ~= 's' then
			units = units .. 's'
		end
		
		-- TODO localize
		local age_with_units = age .. ' ' .. units
		
		local has_bot = is_filled(auto.bot)
		local has_minthreads = is_filled(auto.minthreads)
		if has_bot and has_minthreads then
			age_text = mw.ustring.format(
				cfg.age_bot_threads,
				age_with_units,
				wikilink('User:' .. auto.bot, auto.bot),
				var_or_default(auto.minthreads, cfg.min_threads)
			)
		elseif has_bot then
			age_text = mw.ustring.format(
				cfg.age_bot,
				age_with_units,
				wikilink('User:' .. auto.bot, auto.bot)
			)
		elseif has_minthreads then
			age_text = mw.ustring.format(
				cfg.age_threads,
				age_with_units,
				var_or_default(auto.minthreads, cfg.min_threads)
			)
		else
			age_text = mw.ustring.format(
				cfg.age,
				age_with_units
			)
		end
	end
	
	return mw.html.create('div'):addClass('archives-auto'):wikitext(target_text .. age_text)
end

local function edit_list(frame, auto, list1, archive_list, archive_list_exists, editbox)
	
	local wants_editbox = editbox == 'yes' or editbox == nil or editbox == ''
	-- bogus criteria? `and not is_filled(auto) and is_filled(list1)`
	-- if you've got an archive list you should see the edit box unless you
	-- deliberately disable it
	if archive_list_exists and wants_editbox then
		return mw.html.create('div'):addClass('archives-edit'):wikitext(mw.ustring.format(
			cfg.edit_this_box,
			archive_list:fullUrl('action=edit')
		))
	end
end

local function auto_list(root, is_banner, auto, prefix, start)
	local list_args = {}
	
	if root then list_args.root = root end
	if prefix then list_args.prefix = prefix end
	if start then list_args.start = start end
	
	if is_banner then
		list_args.nobr = 'yes'
	else
		list_args.auto = auto or 'long'
		list_args.nobr = 'no'
	end
	
	return require('Module:Archive list').main(list_args)
end

local function make_title(is_banner, title, archives_disabled, inline_list, index_link, block_list)
	
	if archives_disabled then return end
	
	local title = var_or_default(title, cfg.default_title)
	
	local rendered_title = mw.html.create()
	
	if is_banner then
		local needs_colon_space = false
		if is_filled(inline_list) then needs_colon_space = true end
		
		if index_link ~= '' then
			index_link = mw.ustring.format(' (%s)', index_link)
		end
	
		rendered_title:tag('span')
			:addClass('archives-title')
			:tag('span'):attr('id', 'archives-heading'):wikitext(title):done()
			:wikitext(index_link)
			:wikitext(needs_colon_space and cfg.colon_space or nil)
		
		-- these should be mutually exclusive
		-- should is a famous last word
		if inline_list then
			rendered_title:tag('span')
				:addClass('archives-title-inline-list')
				:wikitext(inline_list)
		end
		if block_list then
			rendered_title:tag('div')
				:addClass('archives-title-block-list')
				:wikitext(block_list)
		end
	else
		if index_link ~= '' then
			index_link = mw.ustring.format(' (%s)', index_link)
		end
	end
	return rendered_title
end

local function foreign(auto, list1)
	-- this logic is seriously fucking screwy
	-- only hope is for the test cases to catch the insanity
	local auto_default = true
	if list1 then
		auto_default = false
	end

	local is_foreign = true
	if (auto and auto == cfg.auto_no) or (not auto and not auto_default) then
		is_foreign = false
	end
	return is_foreign
end

local function make_index(index, auto, list1, list)
	
	local link = ''
	if list or not foreign(auto, list1) then return link end
	if not index or (index and index == 'no') then return link end

	local local_index = mw.getCurrentFrame():callParserFunction(
		'#rel2abs',
		var_or_default('./' .. index, './Archive index')
	)
	
	if mw.title.new(local_index).exists then
		link = wikilink(local_index, cfg.default_index_title)
		return link
	end
	
	local current_title = mw.title.getCurrentTitle()
	local cluebot_index = 'User:ClueBot III/Master Detailed Indices/' .. current_title.fullText

	if mw.title.new(cluebot_index).exists then
		link = wikilink(cluebot_index, cfg.default_index_title)
	end
	return link
end

local function render_list(
	root, auto, list1, archives_disabled, archive_list_title,
	archive_list_exists, list, prefix, inline_list, list_start, is_banner
)
	if archives_disabled then return nil, nil, nil, nil end
	
	-- the logic continues to be screwy
	local is_foreign = foreign(auto, list1)
	
	local inline_title_list
	local block_title_list
	
	if not list and is_foreign then
		local prefix = var_or_default(prefix, nil)
		if archive_list_exists then
			block_title_list = '\n' .. mw.getCurrentFrame():expandTemplate{
				title = archive_list_title
			}
		else
			inline_title_list = auto_list(root, is_banner, auto, prefix, list_start)
		end
	end

	if is_filled(inline_list) then
		inline_title_list = inline_list
	end
	
	-- the post title list is always displayed if list or list1 are present
	local post_title_list = ''
	if list or list1 then
		post_title_list = '\n' .. (list or list1)
	end
	
	return inline_title_list, block_title_list, post_title_list

end

local function add_main_content(frame, is_banner, content)
	
	local is_collapsible = nil
	local is_collapsed = nil
	if content.collapsible and content.collapsible == cfg.collapsible_yes then
		is_collapsible = true
	end
	if content.collapsed and content.collapsed == cfg.collapsed_yes then
		is_collapsed = true
		is_collapsible = true
	end
	
	local archives_disabled = var_or_default(content.archives_disabled, false)
	local root = var_or_default(content.root, nil)
	local auto = var_or_default(content.auto, nil)
	local list = var_or_default(content.list, nil)
	local list1 = var_or_default(content.list1, nil)
	
	local archive_list_name = frame:callParserFunction(
		'#rel2abs',
		var_or_default(content.archive_list, cfg.default_archive_list)
	)
	local archive_list_title = mw.title.new(archive_list_name)
	local archive_list_exists = archive_list_title.exists

	local inline_title_list, block_title_list, post_title_list = render_list(
		root,
		auto,
		list1,
		archives_disabled,
		archive_list_title,
		archive_list_exists,
		list,
		content.prefix,
		content.inline_list,
		content.list_start,
		is_banner
	)
	
	local index_link = make_index(content.index, auto, list1, list)
	
	local main_content = mw.html.create('div')
	main_content
		:addClass('archives-flex-child')
		:addClass(is_collapsible and 'mw-collapsible')
		:addClass(is_collapsed and 'mw-collapsed')
	
	local title_group = make_title(
		is_banner, content.title, archives_disabled, inline_title_list, index_link, block_title_list
	)
	
	local maybe_collapsed_content = mw.html.create()
		:tag('div'):addClass('archives-block-list'):wikitext(post_title_list):done()
		:node(search_box(frame, is_banner, root, content.search))
		:node(note_auto(frame, content.auto_explanation))
		:node(edit_list(
			frame, auto, list1, archive_list_title, archive_list_exists, content.edit_box
		))
		
	if is_collapsible or is_collapsed then
		main_content:tag('div')
			:addClass('archives-collapsible-title')
			:node(title_group)
		main_content:tag('div')
			:addClass('mw-collapsible-content')
			:node(maybe_collapsed_content)
	else
		main_content:node(title_group)
		main_content:node(maybe_collapsed_content)
	end	

	return main_content
end

function p._main(args, frame)

	local is_banner = false
	if (args[cfg.arg.banner] and args[cfg.arg.banner] == cfg.banner_yes) or
		(args[cfg.arg.large] and args[cfg.arg.large] == cfg.banner_yes) then
		is_banner = true
	end
	
	local image = args[cfg.arg.image]
	local has_image = true
	if image and (image == 'none' or image == '') then has_image = false end
	
	local archives = mw.html.create()
	local rendered = archives:tag('div')
		:addClass('archives plainlinks')
		:addClass(is_banner and 'archives-banner' or 'archives-small')
		:addClass(has_image and 'archives-with-image' or nil)
		-- archives-talk has same-ish styles as tmbox tmbox-notice
		-- base styles are same-ish as ombox ombox-notice
		:addClass(talk_other(
			var_or_default(args[cfg.arg.demospace], nil),
			'archives-talk'
		))
		:css('width', var_or_default(args[cfg.arg.box_width], nil))
		:cssText(var_or_default(args[cfg.arg.style], nil))
			
	if has_image then
		rendered:node(add_image({
			image = image,
			alt = args[cfg.arg.alt],
			link = args[cfg.arg.link],
			size = args[cfg.arg.image_size]
		}))
	end
	
	rendered:node(add_main_content(frame, is_banner, {
		archive_list = args[cfg.arg.archive_list],
		archives_disabled = args[cfg.arg.noarchives],
		auto = args[cfg.arg.auto],
		collapsible = args[cfg.arg.collapsible],
		collapsed = args[cfg.arg.collapsed],
		edit_box = args[cfg.arg.edit_box],
		index = args[cfg.arg.index],
		inline_list = args[cfg.arg.inline_list],
		list = args[cfg.arg.list],
		list1 = args[cfg.arg.list1],
		list_start = args[cfg.arg.start],
		prefix = args[cfg.arg.prefix],
		root = args[cfg.arg.root],
		title = args[cfg.arg.title],
		search = {
			search = args[cfg.arg.search],
			prefix = args[cfg.arg.search_prefix],
			width = args[cfg.arg.search_width],
			sbreak = args[cfg.arg.search_break],
			label = args[cfg.arg.search_button_label],
			placeholder = args[cfg.arg.search_placeholder]
		},
		auto_explanation = {
			age = args[cfg.arg.age],
			target = args[cfg.arg.target],
			units = args[cfg.arg.units],
			bot = args[cfg.arg.bot],
			minthreads = args[cfg.arg.minthreads],
			nobot = args[cfg.arg.nobot]
		}
	}))

	return frame:extensionTag{
		name = 'templatestyles', args = { src = cfg.templatestyles }
	} .. tostring(archives)
end

function p.main(frame)
	return p._main(require('Module:Arguments').getArgs(frame), frame)
end

return p