Module:ToggleUtil

From Call of Duty Esports Wiki
Jump to: navigation, search

Documentation for this module may be created at Module:ToggleUtil/doc

local util_vars = require('Module:VarsUtil')
local i18n = require('Module:I18nUtil')

local h = {}

function h.getShowData(data, isSection)
	local default_text = isSection and 'Show All' or 'show'
	local new_data = mw.clone(data)
	new_data.text = data.show_text or default_text
	new_data.verb = 'show'
	new_data.id = data.show_id
	return new_data
end

function h.getHideData(data, isSection)
	local default_text = isSection and 'Hide All' or 'hide'
	local new_data = mw.clone(data)
	new_data.text = data.hide_text or default_text
	new_data.verb = 'hide'
	new_data.show_attr = data.hide_attr
	new_data.hide_attr = data.show_attr
	new_data.hide_class = data.show_class
	new_data.initshown = not data.initshown
	new_data.id = data.hide_id
	return new_data
end

function h.addButton(div, data, addSectionClass)
	local span = div:tag('span')
		:addClass('sections-toggler')
		:attr('data-toggler-hiddenclass', data.hiddenclass)
		:attr('data-toggler-show', data.show_attr)
		:attr('data-toggler-hide', data.hide_attr)
		:attr('id', data.id)
		:addClass(data.hide_class or data.hide_attr) -- hide yourself, and get shown by other
		:wikitext(data.text)
	if data.initshown then
		span:addClass(data.hiddenclass or 'toggle-section-hidden')
	end
	if addSectionClass then
		span:addClass('toggler-section-' .. data.verb) -- purely for style
	end
end

local p = {}

-- for individual show/hides that need a single show-hide all
function p.prepDataByWeek(data, i)
	-- to be used by a parent function before sending stuff here
	-- replaces instances in classes as needed with the current week
	data.show_attr = data.show_attr:format(i)
	data.hide_attr = data.hide_attr:format(i)
	data.show_class = data.show_class:format(i)
	data.hide_class = data.hide_class:format(i)
end

function p.prepDataByWeekAndGame(data, i, j)
	data.show_attr = data.show_attr:format(i, j)
	data.hide_attr = data.hide_attr:format(i, j)
	data.show_class = data.show_class:format(i, i, j)
	data.hide_class = data.hide_class:format(i, i, j)
end

-- to be called directly from a parent function
function p.printToggleHeader(tbl, colspan, display, data)
	local th = tbl:tag('tr')
	:tag('th')
		:attr('colspan',colspan or 1)
	local div = th:tag('div')
		:cssText('position:relative;')
		:tag('div')
			:addClass('table-header-showhide')
	p.printToggleButton(div, data)
	th:wikitext(display)
end

-- in theory could be called directly but mostly should be called from above
function p.printToggleButton(div, data)
	if not data then data = h.makeDefaultSectionToggleData('set') end
	div:wikitext('[')
	h.addButton(div, h.getShowData(data))
	h.addButton(div, h.getHideData(data))
	div:wikitext(']')
end

-- intended to be called externally, makes a section Show All button
function p.printSectionToggler(tbl, data)
	if not tbl then tbl = mw.html.create() end
	local div = tbl:tag('div'):addClass('expand-contract-button'):addClass(data.cssclass)
	local showData = h.getShowData(data, true)
	local hideData= h.getHideData(data, true)
	h.addButton(div, showData, true)
	h.addButton(div, hideData, true)
	return tbl
end
-- end tab/all toggles

-----------------------------------------------
-- simple toggle
-- uses section javascript
----------------------------------------------

function p.printSimpleToggleButton(div, isHidden)
	local data = h.makeDefaultSectionToggleData('set', isHidden)
	div:wikitext('[')
	h.addButton(div, h.getShowData(data))
	h.addButton(div, h.getHideData(data))
	div:wikitext(']')
end

function p.tagSimpleToggledContent(div, isHidden)
	local data = h.makeDefaultSectionToggleData('get', isHidden)
	div:addClass(data.contentClass)
	if isHidden then div:addClass('toggle-section-hidden') end
end

function h.makeDefaultSectionToggleData(verb, isHidden)
	local index = util_vars[verb .. 'GlobalIndex']('TOGGLE_SECTION_INDEX')
	local contentClass = 'default-content-toggle-' .. index
	local buttonClass = 'default-button-toggle-' .. index
	local ret = {
		contentClass = contentClass,
		show_attr = isHidden and contentClass or buttonClass,
		hide_attr = isHidden and buttonClass or contentClass,
	}
	return ret
end

-- separate from the above
-- this assumes a simple single class & single attr
function p.initSectionToggler()
	util_vars.setGlobalIndex('SECTION_TOGGLE_SHOW')
	util_vars.setGlobalIndex('SECTION_TOGGLE_HIDE')
end

function p.tagSectionToggler(tbl, isReversed, hiddenclass)
	local show = 'SECTION_SHOW' .. util_vars.getGlobalIndex('SECTION_TOGGLE_SHOW')
	local hide = 'SECTION_HIDE' .. util_vars.getGlobalIndex('SECTION_TOGGLE_HIDE')
	local showNew = isReversed and hide or show
	local hideNew = isReversed and show or hide
	tbl:addClass('sections-toggler')
		:attr('data-toggler-hiddenclass', hiddenclass)
		:attr('data-toggler-show', showNew)
		:attr('data-toggler-hide', hideNew)
	p.tagSectionToggle(tbl, isReversed, hiddenClass)
end

function p.tagSectionToggle(tbl, isReversed, hiddenclass)
	if isReversed then
		tbl:addClass(hiddenclass or 'toggle-section-hidden')
		tbl:addClass('SECTION_SHOW' .. util_vars.getGlobalIndex('SECTION_TOGGLE_SHOW'))
	else
		tbl:addClass('SECTION_HIDE' .. util_vars.getGlobalIndex('SECTION_TOGGLE_HIDE'))
	end
end
-- end simple section toggler

-- option from list stuff
-- call printOptionFromListTogglers to make the toggles, and oflCellClasses to make the toggled data
-- if the toggled data is physically above the togglers, then call oflInit before doing anything else
function p.oflInit(data)
	-- only run this one time
	if data._INITIALIZED then return end
	local n = util_vars.setGlobalIndex('OFLToggler')
	h.oflInitClasses(data, n)
	data.all = data.all or ('ofl-toggler-%s-all'):format(n)
	data.section = data.section or ('ofl-toggler-%s-section'):format(n)
	data.init = data.init or data.order[1]
	
	-- make sure this doesn't run again
	data._INITIALIZED = true
	
	-- allow this to be called by string if desired
	h.recordDataByKey(data)
end

function p.printOptionFromListTogglers(tbl, data)
	-- @param tbl: HTML object
	-- @param data: table of toggle data, requires key order = array of classes to provide ordering
	-- print the togglers at the start of a section
	-- then call oflCellClasses on each of the things we want to show
	data = h.findData(data)
	-- guarantee pass a table to oflInit, which will do nothing if it's been run for this object before
	p.oflInit(data)
	if not tbl then tbl = mw.html.create() end
	if not data.displays then data.displays = {} end
	local len = #data.order
	for i, val in ipairs(data.order) do
		local span = h.oflPrintOneToggler(tbl, data, val)
		h.oflTogglersAttrs(span, data.attrs, val)
		if i < len then
			tbl:wikitext(data.sep or '|')
		end
	end
	return tbl
end

function p.oflCellClasses(tbl, data, this)
	-- @param tbl: HTML object
	-- @param data: data object from printOptionFromListTogglers, or string key to look up via findData
	-- @param this: one of the classes from data.order
	data = h.findData(data)
	tbl:addClass(data.classes[this])
		:addClass(data.all)
	if data.showall then
		tbl:addClass(data.classes[data.showall])
	end
	if h.oflDoWeAddHiddenclass(data, this) then
		tbl:addClass(data.hiddenclass or 'toggle-section-hidden')
	end
	return tbl
end

function h.recordDataByKey(data)
	-- singleton object to record all active toggles by key
	-- currently only supports same-Lua-session toggles, no variable support
	if not data.key then return end
	if not TOGGLE_DATA_LOOKUPS then TOGGLE_DATA_LOOKUPS = {} end
	TOGGLE_DATA_LOOKUPS[data.key] = data
end

function h.findData(data)
	if type(data) == 'table' then return data end
	if not TOGGLE_DATA_LOOKUPS[data] then
		error(("Trying to look up a key (%s) that doesn't exist"):format(data))
	end
	return TOGGLE_DATA_LOOKUPS[data]
end

function h.oflInitClasses(data, n)
	if data.classes then return end
	data.classes = {}
	for k, v in ipairs(data.order) do
		data.classes[v] = ('ofl-toggle-%s-%s'):format(n, k)
	end
end

function h.oflPrintOneToggler(tbl, data, val, text, isActive)
	if not tbl then tbl = mw.html.create() end
	local span = tbl:tag('span')
		:addClass('optionfromlist-toggler')
		:addClass(data.section)
		:attr('data-toggle-section', data.section)
		:attr('data-toggler-show', data.classes[val])
		:attr('data-toggler-hide', data.all)
		:wikitext(h.getDisplay(data, val))
	if (data.init or data.order[1]) == val then
		span:addClass('active')
	end
	if data.hiddenclass then
		span:attr('data-toggler-hiddenclass', data.hiddenclass)
	end
	return span
end

function h.getDisplay(data, val)
	local output
	if i18n.exists() then
		output = i18n.print(val .. 'Toggle')
	end
	if not output then
		output = data.displays[val] or val
	end
	return output
end

function h.oflTogglersAttrs(span, attrs, val)
	if not attrs then return end
	for attr, data in pairs(attrs) do
		span:attr(attr, data[val])
	end
end

function h.oflDoWeAddHiddenclass(data, this)
	if data.showall == data.init then
		return false
	end
	return this ~= data.init
end

-- always active stuff

function p.printSepToggler(tbl, data, isHideButton)
	local suffix = '_opposite'
	local class = isHideButton and (data.class .. suffix) or data.class
	local otherClass = isHideButton and data.class or (data.class .. suffix)
	local showText = data.show_text or 'show'
	local hideText = data.hide_text or 'hide'
	local text = isHideButton and hideText or showText
	local span = tbl:tag('span')
		:addClass('sections-toggler')
		:wikitext(i18n.print(text .. 'Toggle') or text)
		:attr('data-toggler-show', class)
		:attr('data-toggler-hide', otherClass)
end

function p.sepCellClasses(tbl, data, isActive)
	local class = isActive and (data.class .. '_opposite') or data.class
	tbl:addClass(class)
	if not isActive then
		tbl:addClass(data.hiddenclass or 'toggle-section-hidden')
	end
end

-- popup button
-- all popup buttons are pretty, but we have the choice of what actions to additionally bind
-- by optionally calling the default popupButton or popupButtonLazy
function p.popupButton(tbl, class)
	-- default popup button
	local popup = p.popupButtonPretty(tbl, class)
	popup.button:addClass('popup-button-action')
	return popup
end

function p.popupButtonLazy(tbl, class, parse)
	-- content inside will be computed lazily
	-- the js adds {{}} for you, so only provide the part inside that
	local button = p.popupButton(tbl, class)
	button.button:addClass('popup-button-lazy')
		:attr('data-parse-text', parse)
	return button
end

function p.popupButtonPretty(tbl, class)
	-- does NOT add a button action, can be called directly or via p.popupButton
	-- p.popupButton fetches this then adds the button action and returns
	-- class can be specified to add custom popup-content, popup-button, and popup-wrapper class names
	if not tbl then tbl = mw.html.create() end
	if not settings then settings = {} end
	local span = tbl:tag('span')
	local button = span:tag('div')
		:addClass('popup-button-pretty')
		:wikitext('')
	local wrapper = button:tag('div')
		:addClass('popup-content-wrapper-pretty')
		:addClass('popup-content-wrapper-action')
		:addClass('popup-content-hidden')
	local inner = wrapper:tag('div')
		:addClass('popup-content-inner-pretty')
		:addClass('popup-content-inner-action')
	if class then
		inner:addClass('popup-content-' .. class)
		button:addClass('popup-button-' .. class)
		wrapper:addClass('popup-wrapper-' .. class)
	end
	return {
		tbl = tbl,
		span = span,
		button = button,
		wrapper = wrapper,
		inner = inner
	}
end

function p.allToggleAll(tbl, key)
	if not tbl then tbl = mw.html.create('') end
	local button = tbl:tag('div')
		:addClass('all-toggle-all-toggler')
		:addClass('active')
		:attr('data-all-toggle-key', key)
	local button2 = tbl:tag('div')
		:addClass('all-toggle-all-toggler')
		:addClass('toggle-section-hidden')
		:attr('data-all-toggle-key', key)
	local content = tbl:tag('div')
		:addClass('toggle-section-hidden')
		:addClass('all-toggle-all-toggle')
		:attr('data-all-toggle-key', key)
	return {
		tbl = tbl,
		button = button,
		button2 = button2,
		content = content,
	}
end
return p