Module:Archives

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

Content Disclaimer

Informasi ini disarikan dari Wikipedia dan disajikan kembali untuk tujuan edukasi. Konten tersedia di bawah lisensi CC BY-SA 3.0. Kami tidak bertanggung jawab atas ketidakakuratan data yang bersumber dari kontribusi publik tersebut.

  1. The information displayed on this website is sourced in part or in whole from Wikipedia and has been adapted for the purpose of restating it. We strive to provide accurate and relevant information, however:
  2. There is no guarantee of absolute accuracy. Wikipedia is an open, collaborative project that can be edited by anyone, so information is subject to change.
  3. It is not intended to constitute professional advice. The content displayed is for informational and educational purposes only. For important decisions (e.g., medical, legal, or financial), please consult a professional.
  4. Content copyright. Wikipedia is licensed under the Creative Commons Attribution-ShareAlike License (CC BY-SA). This means that content may be reused with appropriate attribution and shared under a similar license.
  5. Responsible use. Any risk arising from the use of information from this website is entirely the responsibility of the user.