Module:NewsUtil

local util_args = require('Module:ArgsUtil') local util_cargo = require("Module:CargoUtil") local util_html = require("Module:HtmlUtil") local util_map = require('Module:MapUtil') local util_source = require("Module:SourceUtil") local util_table = require("Module:TableUtil") local util_text = require("Module:TextUtil") local util_title = require("Module:TitleUtil") local util_time = require("Module:TimeUtil") local util_toggle = require("Module:ToggleUtil") local util_vars = require("Module:VarsUtil") local i18n = require('Module:i18nUtil') local OD = require('Module:OrderedDict')

local m_region = require('Module:Region') local m_team = require('Module:Team') local m_role = require('Module:Role') local lang = mw.getLanguage('en') local TabsDynamic = require('Module:TabsDynamic').constructor local ContentByHeading = require('Module:ContentByHeading').constructor

local h = {}

local p = {}

p.COLUMNS = { 'DateDisplay', 'Region', 'Player', 'TeamStart', 'RoleStart', 'IsSubStart', 'IsTraineeStart', 'TeamEnd', 'RoleEnd', 'IsSubEnd', 'IsTraineeEnd', 'source_display' }

p.PLAYER_STATUSES = { 'Team', 'Role', 'IsSub', 'IsTrainee' }

p.ALL_POSSIBLE_CHANGES = { 'Team', 'Role', 'IsSub', 'IsTrainee', 'Status', 'RoleModifier', 'RoleDisplay' }

local PLAYER_ARG_PARTS = { 'Player', 'Role', 'Status', 'LoanedFrom', 'LoanedTo', 'MoveType', 'Custom', 'ContractUntil', 'Assistance', 'Event', 'Replacing', 'Reason', 'Phase', 'Sub', 'Trainee', 'Rejoin', 'Order', 'SentenceGroup', 'LeaveDate', 'Unlinked', 'RemainFor', 'RemainForLink', 'AlreadyJoined', 'CurrentTeamPriority', 'SisterTeam', }

function p.setId -- news id set as global NEWS_ID = util_cargo.getUniqueLine(util_vars.setGlobalIndex('newsitem')) end

function p.getId return NEWS_ID or util_cargo.getUniqueLine(util_vars.getGlobalIndex('newsitem')) end

function p.displayDate(str) local y, m, d = str:match('(%d%d%d%d)%-(%d%d)%-') end

function p.getPlayersFromArg(arg) local players = util_args.splitArgsArray(arg, PLAYER_ARG_PARTS) if not next(players) or not next(players[1]) then return OD end return h.getPlayersGuaranteed(arg, players) end

function h.getPlayersGuaranteed(arg, players) local ret = OD for _, playerData in ipairs(players) do		h.addPlayerData(ret, playerData) end return ret end

function h.addPlayerData(ret, playerData) if not playerData.Player then return end playerData.player = playerData.Player playerData.PlayerLink = util_title.target(playerData.Player) playerData.IsSub = util_args.castAsBool(playerData.Sub) playerData.IsTrainee = util_args.castAsBool(playerData.Trainee) local role = playerData.Role playerData.Role = util_map.splitAndConcat(playerData.Role, '%s*;%s*', h.getRoleStorename, '/', playerData) playerData.RoleDisplay = util_map.splitAndConcat(role, '%s*;%s*', h.getRoleDisplay, '/', playerData) ret:set(playerData.Player:gsub('_', ' '), playerData) playerData.role = playerData.Role playerData.sub = playerData.IsSub playerData.trainee = playerData.IsTrainee end

function h.getRoleStorename(role, obj) -- pre or post return m_role.storename(role, { sub = obj.Sub, trainee = obj.Trainee }) or role end

function h.getRoleDisplay(role, obj) -- pre or post return m_role.medium(role, { sub = obj.Sub, trainee = obj.Trainee }) or role end

function p.getNewsCargoFieldsFromArgs(args) local ret = { _table = 'NewsItems', Tournaments = util_map.splitAndConcat(			args.tournaments or args.tournament,			nil,			util_title.target		), Teams = util_map.splitAndConcat(			args.teams or args.team,			nil,			m_team.teamlinkname		), Date_Sort = args.date or util_vars.getVar('Date'), Date_Display = args.display_date and args.display_date:gsub('x','?'), Region = m_region.medium(args.region), IsApproxDate = util_args.castAsBool(args.approx), Tags = args.tags, Sentence = args.Sentence, SentenceWithDate = h.getSentenceWithDate(args), Source = args.source, N_LineInDate = util_vars.setGlobalIndex('N_LineInDate'), NewsId = NEWS_ID, ExcludeFrontpage = util_args.castAsBool(args.no_frontpage), ExcludePortal = util_args.castAsBool(args.no_portal), Players = args.players or args.player, }	return ret end

function p.getExcludedPreloadsWhereCondition(list) local tbl = { h.getExcludedPreloadsToIgnoreCompletely(list), h.getExcludedPreloadsToIgnoreHalf(list.join, 'Join'), h.getExcludedPreloadsToIgnoreHalf(list.leave, 'Leave'), }	return util_cargo.concatWhere(tbl) end

function h.getExcludedPreloadsToIgnoreCompletely(list) return util_map.formatAndConcat(		list,		' AND ',		'COALESCE(RC.Preload, News.Preload, "") != "%s"'	) end

function h.getExcludedPreloadsToIgnoreHalf(list, direction) if not list or #list == 0 then return nil end return ('RC.Direction!="%s" OR (%s)'):format(		direction,		h.getExcludedPreloadsToIgnoreCompletely(list)	) end

function p.getExcludedNewsPreloadsWhereCondition(list) if not list or #list == 0 then return nil end return util_cargo.concatWhere(		util_map.format( list, 'COALESCE(News.Preload,"") != "%s"' )	) end

function p.getRosterPortalDatesWhereCondition(period, dateFieldName) local ret = { ('Dates.PeriodName="%s"'):format(period), ('%s > Dates.DateStart'):format(dateFieldName), ('%s < Dates.DateEnd'):format(dateFieldName), }	return ret end

function p.getRCFieldsFromPlayerAndArgs(player, args) local ret = { _table = 'RosterChanges', Player = player.Player, Date_Sort = util_vars.getVar('Date'), Date_Display = args.date or args.Date_Sort, Source = args.source, Region = args.region and m_region.medium(args.region) or '', CurrentTeamPriority = player.CurrentTeamPriority or args.team_priority, Team = m_team.teamlinkname(args.team), NewsId = p.getId, RoleModifier = p.getRoleModifierFromArgs(player, 'Sub', 'Trainee'), Role = player.Role, PlayerUnlinked = player.Unlinked, IsGCD = util_source.isGCD(args.Source), }	return ret end

function p.storeRosterChangesRow(row) row.RosterChangeId = h.setAndGetRosterChangeId(row) util_cargo.store(row) end

function h.setAndGetRosterChangeId(row) local tbl = { mw.title.getCurrentTitle.text, row.Player, row.Team or 'No Team', util_vars.setGlobalIndex('rosterChangePlayer' .. row.Player .. (row.Team or '_')), }	return util_table.concat(tbl, '_') end

-

-- for use when writing the date out as a sentence -- wraps h.getDisplayDateForSentence for use outside of this module -- renames args as expected from args instead of Cargo function p.getDisplayDateForSentence(row) -- @param row: expects keys Date_Display, Date, and IsApproxDate -- @returns: Month D, with (approx.) if needed return h.getDisplayDateForSentence({		display_date = row.Date_Display,		approx = row.IsApproxDate,		date = row.Date	}) end

function h.getSentenceWithDate(args) if not args.Sentence then return nil end return ('%s, %s'):format(h.getDisplayDateForSentenceOnDataPage(args), args.Sentence) end

function h.getDisplayDateForSentenceOnDataPage(args) return h.getDisplayDateForSentence({		display_date = args.display_date,		approx = args.approx,		date = util_vars.getVar('Date')	}) end

function h.getDisplayDateForSentence(data) -- @param data: expects keys display_date, date, and approx -- @returns: Month D, with (approx.) if needed if not data.display_date and not util_args.castAsBool(data.approx) then return lang:formatDate('F j', data.date) end return util_time.strToDateStrFuzzyWithoutYear(		data.display_date or data.date,		util_args.castAsBool(data.approx)	) end

-- for use when printing mmm YYYY dates with toggle to exact in data tables function p.getDateAndRefDisplayForTable(row, when) if not (row['Date_Display' .. when] or row['Date' .. when]) then return nil end return ('%s%s'):format(		p.getDateDisplayForTable(row, when),		util_source.makeRef(row['Source' .. when]) or ''	) end

function p.getDateDisplayForTable(row, when) -- @param row: has keys Join/Leave for Date_Display, Date, and IsApproxDate -- @param when: "Join" or "Leave" -- @returns: mmm YYYY format date with approx equals sign as needed -- call this directly to avoid printing a ref immediately if not (row['Date_Display' .. when] or row['Date' .. when]) then return nil end local displays = { h.getToggleAndDisplay(row, when, 'approx', p.formatDateApproxForTableDisplay), h.getToggleAndDisplay(row, when, 'exact', h.formatDateExactForTableDisplay), }	return util_table.concat(displays, '', tostring) end

function h.getToggleAndDisplay(row, when, toggleName, f)	return util_toggle.oflCellClasses(		util_html.span(f(h.getDisplayDateParams(row, when))),		'date',		toggleName	) end

function h.getDisplayDateParams(row, when) return row['Date_Display' .. when] or row['Date' .. when], row['IsApproxDate' .. when] end

function p.formatDateApproxForTableDisplay(str, isApprox) if not str then return end local date = util_time.strToDateFuzzy(str) if not date.year then return '??? ????' end if not date.month then return '??? ' .. date.year end if not date.day then str = str:gsub('%?%?', '01') end return h.getApproxModifierForTable(isApprox) .. lang:formatDate('M Y', str) end

function h.formatDateExactForTableDisplay(str, isApprox) if not str then return nil end return h.getApproxModifierForTable(isApprox) .. str end

function h.getApproxModifierForTable(isApprox) return isApprox and '≈' or '' end -- end helper functions for p.getDateDisplayForTable

function p.getSentenceAndRefDisplay(row, when) local popup = util_toggle.popupButton(td) popup.inner:wikitext(row['Sentence' .. when]) :wikitext(util_source.makeRef(row['Source' .. when])) popup.button:addClass('popup-ref-button') popup.wrapper:addClass('popup-ref-wrapper') popup.inner:addClass('popup-ref-inner') return tostring(popup.button) end

function p.makeSentenceOutput(args, newsCargo) local tr = mw.html.create('tr') tr:addClass('news-data-sentence') local td = tr:tag('td') :attr('colspan', #p.COLUMNS) :addClass('news-data-sentence-cell') local div = td:tag('div') :addClass('news-data-sentence-div') div:tag('div') :addClass('news-data-sentence-wrapper') :wikitext(h.getSentenceWithDate(args)) local button = h._printROButton(div, newsCargo) return tr end

function p.printROButton(td, pagelist, team) local popup = util_toggle.popupButtonPretty(td) popup.button :addClass('news-data-ro') :attr('data-to-refresh', util_table.concat(pagelist), ',') :attr('data-ro-team', team) popup.wrapper:addClass('news-data-ro-wrapper') popup.inner:addClass('news-data-ro-inner') return popup.button end

function h._printROButton(td, newsCargo) p.printROButton(td, h.getPagesToRefresh(newsCargo), newsCargo.Subject) end

function h.getPagesToRefresh(newsCargo) return util_table.mergeArrays(		util_map.arrayInPlaceAndMerge( { 'Players', 'Teams', 'Tournaments' }, h.getPagesFromKey, newsCargo ),		{ 'League of Legends Esports Wiki' }	) end

function h.getPagesFromKey(key, newsCargo) return util_text.splitNonempty(newsCargo[key]) end

function p.printEditButton(li, page) li:tag('div') :addClass('content-edit-button') :wikitext(util_text.intLink(page, 'e')) end

function p.sectionsOrTabs(byDate, threshold, tabs, headingLevel) headingLevel = headingSize or 3 local total = 0 for _, year in ipairs(byDate) do		total = total + #byDate[year] end if total > threshold then return TabsDynamic(tabs, #tabs) end return ContentByHeading(tabs, headingLevel) end

function p.roleOrStaffImage(role, sub, trainee) return m_role.onlyimage(role, {		sub = sub,		trainee = trainee,		skipdefault = true,		title = role,		default = { role = 'Staff' },	}) end

function p.notWhen(when) if when == 'Start' then return 'End' end return 'Start' end

function p.getRoleModifierFromArgs(args, subArgName, traineeArgName) subArgName = subArgName or 'sub' traineeArgName = traineeArgName or 'trainee' if args[subArgName] and util_args.castAsBool(args[subArgName]) then return 'Sub' elseif args[traineeArgName] and util_args.castAsBool(args[traineeArgName]) then return 'Trainee' end return nil end

return p