Для документации этого модуля может быть создана страница Модуль:Wikidata/chronology/doc
local p = {} -- p stands for package -- technical functions for takeAdjacentNumbersFromStrings function isYear(number) -- TODO: settings not hardcoded return number >= 1800 and number <= 2100 end function isAr(number) return number >= 0 and number < 100 end function notTooFar(number1, number2, maximalPeriod) return number2 - number1 > 0 and number2 - number1 <= maximalPeriod end -- takes two strings and returns either two substrings that form the only difference between them or nil -- considers several possible formats of substrings given in options.formats function takeAdjacentNumbersFromStrings(options, string1, string2) if type(string1) == 'string' and type(string2) == 'string' then local formats = options.formats or '' -- TODO: not repeat with properties if formats == '' then formats = 'year, year/ar, year/year' elseif formats == '-' then formats = '' end local formats = mw.text.split(formats, ', ?') local line = '!' .. string1 .. '!!' .. string2.. '!' -- -- TODO: without hacks local maximalPeriod = tonumber(options.maximalPeriod) or 5 -- TODO: here or in main function? for _, format in pairs(formats) do if format == 'year' or format == 'number' then local match = {mw.ustring.match(line, '^(.*%D)(%d+)(%D.*)%1(%d+)%3$')} if #match > 0 then local number1 = tonumber(match[2]) local number2 = tonumber(match[4]) if notTooFar(number1, number2, maximalPeriod) then if (format == 'year' and isYear(number1) and isYear(number2)) or (format == 'number') then return {number1, number2} end end end elseif format == 'year/ar' or format == 'year/year' then local match = {mw.ustring.match(line, '^(.*%D)((%d+)[-–\/](%d+))(%D.*)%1((%d+)\/(%d+))%5$')} if #match > 0 then local period1 = match[2] local period1_start = tonumber(match[3]) local period1_end = tonumber(match[4]) local period2 = match[6] local period2_start = tonumber(match[7]) local period2_end = tonumber(match[8]) if notTooFar(period1_start, period2_start, maximalPeriod) and isYear(period1_start) and isYear(period2_start) and period2_start - period1_start == period2_end - period1_end then if (format == 'year/ar' and isAr(period1_end) and isAr(period2_end)) or (format == 'year/year' and isYear(period1_end) and isYear(period2_end)) then return {period1, period2} end end end end end end return nil end -- takes two Wikidata entities and returns either two strings or nil -- considers sitelinks and labels in the local langauge and in English function takeAdjacentNumbersFromEntities(options, entity1, entity2) if entity1 and entity2 then local adjacentNumbers = nil local languageCodes = {mw.getContentLanguage():getCode(), 'en'} for _, languageCode in pairs(languageCodes) do local wikiCode = languageCode .. 'wiki' local sitelink1 = entity1:getSitelink(wikiCode) local sitelink2 = entity2:getSitelink(wikiCode) adjacentNumbers = takeAdjacentNumbersFromStrings(options, sitelink1, sitelink2) if adjacentNumbers then return adjacentNumbers end local label1 = entity1:getLabel(languageCode) -- TODO: get rid of fallback? local label2 = entity2:getLabel(languageCode) adjacentNumbers = takeAdjacentNumbersFromStrings(options, label1, label2) if adjacentNumbers then return adjacentNumbers end end end return nil end function formatAdjacentSnak(context, options, snak) local direction = options.direction or '' if snak and snak.datavalue and snak.datavalue.value and snak.datavalue.value.id then local mainText = nil local adjacentEntity = mw.wikibase.getEntity(snak.datavalue.value.id) if direction == 'P155' then -- previous local adjacentNumbers = takeAdjacentNumbersFromEntities(options, adjacentEntity, options.entity) -- or reverse order if adjacentNumbers then mainText = adjacentNumbers[1] -- or 2 end elseif direction == 'P156' then -- next local adjacentNumbers = takeAdjacentNumbersFromEntities(options, options.entity, adjacentEntity) if adjacentNumbers then mainText = adjacentNumbers[2] end end -- options should not be changed, as they are reused for P155 and P156 local optionsCopy = {} for k, v in pairs(options) do optionsCopy[k] = v end if (not optionsCopy.text) and mainText then local prefix = options.prefix or '' local postfix = options.postfix or '' optionsCopy.text = prefix .. mainText .. postfix end local link = context.formatSnak(optionsCopy, snak) if mainText or (options.formats and options.formats == '-') then return link else return link .. '[[Категория:Википедия:Статьи с несокращаемой хронологией]]' end end return nil end -- function is available from outside, see documentation function p.formatAdjacentProperty(context, options) if (not context) then error('context not specified'); end; if (not options) then error('options not specified'); end; if (not options.entity) then error('options.entity missing'); end; if options.value == '-' then return '' end if options.value then return options.value end local properties = options.property or '' -- TODO: properties vs. property? if properties == '' then properties = 'Q' elseif properties == '-' then properties = '' end local properties = mw.text.split(properties, ', ?') local direction = options.direction or '' -- TODO: not repeating inside local formattedClaims = {} for _, property in pairs(properties) do if property == 'Q' then local claims = context.selectClaims(options, direction) if claims then for _, claim in pairs(claims) do if claim.mainsnak then local link = formatAdjacentSnak(context, options, claim.mainsnak) if link and link ~= '' then local formattedClaim = '<span class="wikidata-claim" data-wikidata-property-id="' .. direction .. '" data-wikidata-claim-id="' .. claim.id .. '">' .. link .. '</span>' table.insert(formattedClaims, formattedClaim) end end end end elseif mw.ustring.match(property, '^P%d+$') then local claims = context.selectClaims(options, property) if claims then for _, claim in pairs(claims) do if claim.qualifiers and claim.qualifiers[direction] then for _, snak in pairs(claim.qualifiers[direction]) do local link = formatAdjacentSnak(context, options, snak) if link and link ~= '' then local formattedClaim = '<span class="wikidata-claim" data-wikidata-property-id="' .. property .. '" data-wikidata-claim-id="' .. claim.id .. '">' .. link .. '</span>' table.insert(formattedClaims, formattedClaim) end end end end end end end -- from wikidata.selectClaims if options.limit and options.limit ~= '' and options.limit ~= '-' then local limit = tonumber(options.limit, 10); while #formattedClaims > limit do table.remove(formattedClaims); end end -- from wikidata.formatPropertyDefault local out = mw.text.listToText(formattedClaims, options.separator, options.conjunction) if out ~= '' then if options.before then out = options.before .. out end if options.after then out = out .. options.after end end return out end return p