تضامنًا مع حق الشعب الفلسطيني |
وحدة:Navseasoncats/ملعب
اذهب إلى التنقل
اذهب إلى البحث
هذه صفحة ملعب الوحدة لصفحة وحدة:Navseasoncats (فرق). |
هذه الوحدة مستخدمة في عدد كبير من الصفحات (+257757) . لتفادي خلق بلبلة على نطاق واسع من الصفحات وزيادة الأعباء على الخوادم، يجب تجربة أي تعديل في هذه الصفحات الفرعية /ملعب أو /تجربة أو في ملعبك. بعدها يمكنك اضافة التعديلات دفعة واحدة، ورجاءً، لا تنسَ مناقشة أمر التعديلات أوّلًا قبل القيام بها. |
هذه الوحدة تعتمد على الوحدات الأخرى التالية: |
صفحات متعلقة |
---|
عن
الاستخدام
- استخدام نموذجي
{{تصنيف موسم}}
- تحديد حد أدنى و/أو أقصى للسنة لعرضه
{{تصنيف موسم|min=-100}}
{{تصنيف موسم|min=100 ق م}}
{{تصنيف موسم|min=1753|max=1810}}
{{تصنيف موسم|max=2025}}
- حالات إستثنائية
{{تصنيف موسم|cat=ألبومات عقد 2010}}
— أن تتصرف كما لو وضعت على|cat=
: فكر في استخدام {{زوج تصنيف}} بدلاً من|cat=
اختبارات
لاختبار ناتج القالب على اسم تصنيف معين، استخدم الوسيط |testcase=
، واستخدم |testcasegap=
عند الحاجة:
{{تصنيف موسم|testcase=طيور وصفت في 1758|min=1753}}
←
{{تصنيف موسم|ملعب=نعم|testcase=انتخابات 2019|max=3}}
←
|
{{تصنيف موسم|ملعب=نعم|testcase=محركات طائرات مكبسية 1930–1939|testcasegap=1}}
←
|
تصحيح الأخطاء
{{تصنيف موسم|ملعب={{ملعب أخر|نعم}}|testcase=كوارث طبيعية 1994 | max=2005 | skip-gaps=yes | list-all-links=yes}}
تصانيف التتبع
إذا واجه القالب مشكلة ، فإنه يعرض رسالة خطأ أو يضع تصنيف أو أكثر من تصنيفات التتبع التالية:
صيانة مطلوبة
- تصنيف:صيانة شريط تصنيف فشل في إنشاء صندوق شريط (287 صفحة)
- تصنيف:تصنيف موسم خطأ في إعادة التوجيه (0 صفحة)
- تصنيف:صيانة شريط تصنيف مدى مختصر (57 صفحة)
- تصنيف:تصنيف موسم تحويل مدى (دليل الأسلوب) (5 صفحة)
- تصنيف:تصنيف موسم نهاية المدى (فارغ) (0 صفحة)
- تصنيف:صيانة شريط تصنيف لا يستخدم شرطة (2٬400 صفحة)
- تصنيف:تصنيف موسم في مقالة (1 صفحة)
الصيانة ممكنة
- تصنيف:صيانة شريط تصنيف معزول (9٬600 صفحة)
- تصنيف:تصنيف موسم حجم الفارق (448 صفحة)
- تصنيف:صيانة شريط تصنيف يستخدم cat (7٬385 صفحة)
- تصنيف:صيانة شريط تصنيف يستخدم testcase (0 صفحة)
- تصنيف:تصنيف موسم يستخدم وسيط غير معروف (756 صفحة)
صيانة الوحدة ممكنة
- تصنيف:تصنيف موسم تحويل تصنيف سنة (أخرى) (1 صفحة)
- تصنيف:تصنيف موسم تحويل مدى (أخرى) (0 صفحة)
للتتبع فقط
- تصنيف:تصنيف موسم تحويل مدى (تغيير القاعدة) (0 صفحة)
- تصنيف:تصنيف موسم تحويل مدى (نهاية) (0 صفحة)
- تصنيف:تصنيف موسم مدى الفارق (2٬698 صفحة)
- تصنيف:تصنيف موسم مدى غير منتظم (54 صفحة)
- تصنيف:تصنيف موسم مدى غير منتظم الطول-0 (558 صفحة)
- تصنيف:تصنيف موسم نهاية المدى (حالي) (0 صفحة)
- تصنيف:تصنيف موسم تحويل تصنيف موسم تلفزيون (0 صفحة)
- تصنيف:تصنيف موسم تحويل تصنيف عقد (734 صفحة)
- تصنيف:تصنيف موسم تحويل تصنيف سنة (216 صفحة)
- تصنيف:تصنيف موسم تحويل تصنيف سنة (تغيير) (0 صفحة)
- تصنيف:تصنيف موسم تحويل تصنيف الأرقام الرومانية (0 صفحة)
- تصنيف:تصنيف موسم تحويل تصنيف ترتيب (206 صفحة)
- تصنيف:تصنيف موسم تحويل تصنيف ترتيب-كلمة (0 صفحة)
- تصنيف:تصنيف موسم يستخدم وسيط skip-gaps (0 صفحة)
- تصنيف:تصنيف موسم سنة ومدى (195 صفحة)
- تصنيف:تصنيف موسم سنة وعقد (132٬041 صفحة)
- تصنيف:تصنيف موسم عقد وقرن (28٬157 صفحة)
طالع أيضاً
require[[strict]]
local p = {}
local horizontal = require('Module:List').horizontal
--[[==========================================================================]]
--[[ Globals ]]
--[[==========================================================================]]
local currtitle = mw.title.getCurrentTitle()
local nexistingcats = 0
local errors = ''
local testcasecolon = ''
local testcases = string.match(currtitle.subpageText, '^testcases') or string.match(currtitle.subpageText, '^مختبر')
if testcases then testcasecolon = ':' end
local navborder = true
local followRs = true
local skipgaps = false
local listall = false
local tlistall = {}
local tlistallbwd = {}
local tlistallfwd = {}
local tracking_cats_dir = { --when reindexing, Ctrl+H 'trackcat(1,' & 'ttrackingcats[1]'
'صيانة شريط تصنيف يستخدم cat',
'صيانة شريط تصنيف يستخدم testcase',
'تصنيف موسم يستخدم وسيط غير معروف',
'صيانة شريط تصنيف لا يستخدم شرطة',
'صيانة شريط تصنيف مدى مختصر',
'تصنيف موسم تحويل مدى (تغيير القاعدة)',
'Navseasoncats range redirected (var change)',
'تصنيف موسم تحويل مدى (نهاية)',
'تصنيف موسم تحويل مدى (دليل الأسلوب)',
'تصنيف موسم تحويل مدى (أخرى)',
'تصنيف موسم مدى الفارق',
'تصنيف موسم مدى غير منتظم',
'تصنيف موسم مدى غير منتظم الطول-0',
'تصنيف موسم نهاية المدى (حالي)',
'تصنيف موسم نهاية المدى (فارغ)',
'صيانة شريط تصنيف معزول',
'تصنيف موسم حجم الفارق',
'تصنيف موسم تحويل تصنيف عقد',
'تصنيف موسم تحويل تصنيف سنة',
'تصنيف موسم تحويل تصنيف سنة (تغيير)', --new
'تصنيف موسم تحويل تصنيف سنة (أخرى)',
'تصنيف موسم تحويل تصنيف الأرقام الرومانية',
'تصنيف موسم تحويل تصنيف ترتيب',
'تصنيف موسم تحويل تصنيف ترتيب-كلمة',
'تصنيف موسم تحويل تصنيف موسم تلفزيون',
'تصنيف موسم يستخدم وسيط skip-gaps',
"تصنيف موسم سنة ومدى",
"تصنيف موسم سنة وعقد",
"تصنيف موسم عقد وقرن" ,
"تصنيف موسم في مقالة" ,
"تصنيف موسم خطأ في إعادة التوجيه",
}
local ttrackingcats = { --when reindexing, Ctrl+H 'trackcat(13,' & 'ttrackingcats[16]'
'', -- [1] placeholder for [[تصنيف:صيانة شريط تصنيف يستخدم cat]]
'', -- [2] placeholder for [[تصنيف:صيانة شريط تصنيف يستخدم testcase]]
'', -- [3] placeholder for [[تصنيف:تصنيف موسم يستخدم وسيط غير معروف]]
'', -- [4] placeholder for [[تصنيف:صيانة شريط تصنيف لا يستخدم شرطة]]
'', -- [5] placeholder for [[تصنيف:صيانة شريط تصنيف مدى مختصر]]
'', -- [6] placeholder for [[تصنيف:تصنيف موسم تحويل مدى (تغيير القاعدة)]]
'', -- [7] placeholder for [[Category:Navseasoncats range redirected (var change)]] --new
'', -- [8] placeholder for [[Category:Navseasoncats range redirected (end)]]
'', -- [9] placeholder for [[تصنيف:تصنيف موسم تحويل مدى (دليل الأسلوب)]]
'', --[10] placeholder for [[Category:Navseasoncats range redirected (other)]]
'', --[11] placeholder for [[تصنيف:تصنيف موسم مدى الفارق]]
'', --[12] placeholder for [[تصنيف:تصنيف موسم مدى غير منتظم]]
'', --[13] placeholder for [[تصنيف:تصنيف موسم مدى غير منتظم الطول-0]]
'', --[14] placeholder for [[Category:Navseasoncats range ends (present)]]
'', --[15] placeholder for [[Category:Navseasoncats range ends (blank, MOS)]]
'', --[16] placeholder for [[تصنيف:صيانة شريط تصنيف معزول]]
'', --[17] placeholder for [[تصنيف:تصنيف موسم حجم الفارق]]
'', --[18] placeholder for [[تصنيف:تصنيف موسم تحويل تصنيف عقد]]
'', --[19] placeholder for [[تصنيف:تصنيف موسم تحويل تصنيف سنة]]
'', --[20] placeholder for [[Category:Navseasoncats year redirected (var change)]]
'', --[21] placeholder for [[تصنيف:تصنيف موسم تحويل تصنيف سنة (أخرى)]]
'', --[22] placeholder for [[تصنيف:تصنيف موسم تحويل تصنيف الأرقام الرومانية]]
'', --[23] placeholder for [[تصنيف:تصنيف موسم تحويل تصنيف ترتيب]]
'', --[24] placeholder for [[تصنيف:تصنيف موسم تحويل تصنيف ترتيب-كلمة]]
'', --[25] placeholder for [[تصنيف:تصنيف موسم تحويل تصنيف موسم تلفزيون]]
'', --[26] placeholder for [[تصنيف:تصنيف موسم يستخدم وسيط skip-gaps]]
'', --[27] placeholder for [[تصنيف:تصنيف موسم سنة ومدى]]
'', --[28] placeholder for [[تصنيف:تصنيف موسم سنة وعقد]]
'', --[29] placeholder for [[تصنيف:تصنيف موسم عقد وقرن]]
'', --[30] placeholder for [[Category:Navseasoncats in mainspace]]
'', --[31] placeholder for [[Category:Navseasoncats redirection error]]
}
local avoidself = (not string.match(currtitle.text, 'Navseasoncats with') and
not string.match(currtitle.text, 'Navseasoncats.*/شرح') and
not string.match(currtitle.text, 'Navseasoncats.*/ملعب') and
not string.match(currtitle.text, 'تصنيف موسم.*/شرح') and
not string.match(currtitle.text, 'تصنيف موسم.*/ملعب') and
currtitle.text ~= 'Navseasoncats' and
currtitle.text ~= 'تصنيف_موسم' and
currtitle.nsText ~= 'User_talk' and
currtitle.nsText ~= 'نقاش_المستخدم' and
currtitle.nsText ~= 'نقاش_المستخدمة' and
currtitle.nsText ~= 'Template_talk' and
currtitle.nsText ~= 'نقاش_القالب' and
(currtitle.nsText ~= 'Template' or currtitle.nsText ~= 'قالب' or testcases)) --avoid nested transclusion errors (i.e. {{Infilmdecade}})
local er_counts = 0
--[[==========================================================================]]
--[[ Utility & category functions ]]
--[[==========================================================================]]
--Determine if a category exists (in a function for easier localization).
local function catexists( title )
return mw.title.new( title, 'تصنيف' ).exists
end
--Error message handling.
function p.errorclass( msg )
return mw.text.tag( 'span', {class='error mw-ext-cite-error'}, '<b>Error!</b> '..string.gsub(msg, '&#', '&#') )
end
--Failure handling.
function p.failedcat( errors, sortkey )
if avoidself then
return (errors or '') .. '***صيانة شريط تصنيف فشل في إنشاء صندوق شريط***' ..
'[[' .. testcasecolon .. 'تصنيف:صيانة شريط تصنيف فشل في إنشاء صندوق شريط|' .. (sortkey or 'O') .. ']]\n'
end
return ''
end
--Tracking cat handling.
-- key: 15 (when reindexing ttrackingcats{}, Ctrl+H 'trackcat(13,' & 'ttrackingcats[16]')
-- cat: 'Navseasoncats isolated'; '' to remove
--Used by main, all nav_*(), & several utility functions.
local function trackcat( key, cat )
cat = tracking_cats_dir[key]
if avoidself and key and cat then
if cat ~= '' then
ttrackingcats[key] = '[[' .. testcasecolon .. 'تصنيف:' .. cat .. ']]'
else
ttrackingcats[key] = ''
end
end
return
end
--Check for unknown parameters.
--Used by main only.
local function checkforunknownparams( tbl )
local knownparams = {
['min'] = 'min',
['max'] = 'max',
['cat'] = 'cat',
['testcase'] = 'testcase',
['testcasegap'] = 'testcasegap',
['skip-gaps'] = 'skip-gaps',
['list-all-links'] = 'list-all-links',
['follow-redirects'] = 'follow-redirects',
}
for k, _ in pairs (tbl) do
if knownparams[k] == nil then
trackcat(3, 'Navseasoncats using unknown parameter')
break
end
end
end
--Check for nav_*() navigational isolation (not necessarily an error).
--Used by all nav_*().
local function isolatedcat()
if nexistingcats == 0 then
trackcat(16, 'Navseasoncats isolated')
end
end
--Returns the target of {{تحويل تصنيف}}, if it exists, else returns the original cat.
--{{Title year}}, etc., if found, are evaluated.
--Used by catlinkfollowr(), and so indirectly by all nav_*().
-- local rtarget_cash = {}
local function rtarget( frame, cat )
local catcontent = mw.title.new( cat or '', 'تصنيف' ):getContent()
if string.match( catcontent or '', '{{ *تحويل' ) then --prelim test
local regex = {
--the following 11 pages (7 condensed) redirect to [[قالب:تحويل تصنيف]] (as of 6/2019):
'{{ *[Cc]ategory *[Rr]edirect', --most likely match 1st
'{{ *[Cc]at *redirect', --444+240 transclusions
'{{ *[Cc]at *redir', --8+3
'{{ *[Cc]ategory *move', --6
'{{ *[Cc]at *red', --6
'{{ *[Cc]atr', --4
'{{ *[Cc]at *move', --0
'{{تحويل تصنيف',
}
for _, v in pairs (regex) do
local rtarget = mw.ustring.match( catcontent, v..'%s*|%s*([^|}]+)' )
if rtarget then
if string.match(rtarget, '{{') then --{{Title year}}, etc., exists; evaluate
local regex_ty = '%s*|%s*([^{}]*{{([^{|}]+)}}[^{}]-)%s*}}' --eval null-param templates only; expanded if/as needed
local rtarget_orig, ty = mw.ustring.match( catcontent, v..regex_ty )
if rtarget_orig then
local ty_eval = frame:expandTemplate{ title = ty, args = { page = cat } } --frame:newChild doesn't work, use 'page' param instead
local rtarget_eval = mw.ustring.gsub(rtarget_orig, '{{%s*'..ty..'%s*}}', ty_eval )
-- rtarget_cash[cat] = rtarget_eval
return rtarget_eval
else --sub-parameters present; track & return default
trackcat(31, 'Navseasoncats redirection error')
end
end
rtarget = mw.ustring.gsub(rtarget, '^1%s*=%s*', '')
rtarget = string.gsub(rtarget, '^[Cc]ategory:', '')
rtarget = string.gsub(rtarget, '^تصنيف:', '')
-- rtarget_cash[cat] = rtarget
return rtarget
end
end --for
end --if
return cat
end
--Similar to {{LinkCatIfExists2}}: make a piped link to a category, if it exists;
--if it doesn't exist, just display the greyed link title without linking.
--Follows {{تحويل تصنيف}}s.
--Returns {
-- ['cat'] = cat,
-- ['catexists'] = true,
-- ['rtarget'] = <#R target>,
-- ['navelement'] = <#R target navelement>,
-- ['displaytext'] = displaytext,
-- } if #R followed;
--returns {
-- ['cat'] = cat,
-- ['catexists'] = <true|false>,
-- ['rtarget'] = nil,
-- ['navelement'] = <cat navelement>,
-- ['displaytext'] = displaytext,
-- } otherwise.
--Used by all nav_*().
local catlinkfollowr_cash = {}
local function catlinkfollowr( frame, cat, displaytext, displayend )
cat = mw.text.trim(cat or '')
displaytext = mw.text.trim(displaytext or '')
--mw.log('displaytext:' .. displaytext)
if string.match( cat , ".*%s*ق%s*م%s*.*" ) and not string.match( displaytext .. ' ' , ".*%s*ق%s*م%s*.*" ) then
displaytext = displaytext .. " ق م"
end
-- --mw.log("cat:'" .. cat .. "',displaytext:'" .. displaytext .. "'")
displayend = displayend or false --bool flag to override displaytext IIF the cat/target is terminal (e.g. "2021–present" or "2021–")
local grey = '#888'
local disp = cat
if displaytext ~= '' then --use 'displaytext' parameter if present
disp = mw.ustring.gsub(displaytext, '%s+%(.+$', ''); --strip any trailing disambiguator
end
local link, nilorR
--local exists = mw.title.new( cat, 'تصنيف' )
local exists = catexists(cat)
if exists then
nexistingcats = nexistingcats + 1
if followRs then
local R = rtarget(frame, cat) --find & follow #R
if R ~= cat then --#R followed
nilorR = R
end
if displayend then
local y, hyph, ending = mw.ustring.match(R, '^.-(%d+)([–-])(.*)$')
if ending == 'present' then
disp = y..hyph..ending
elseif ending == '' then
disp = y..hyph..'<span style="visibility:hidden">'..y..'</span>' --hidden y to match spacing
end
end
link = '[[:تصنيف:' .. R .. '|' .. disp .. ']]'
else
link = '[[:تصنيف:' .. cat .. '|' .. disp .. ']]'
end
else
link = '<span style="color:'..grey..'">'..disp..'</span>'
end
if listall then
if nilorR then --#R followed
table.insert( tlistall, '[[:تصنيف:' .. cat .. ']] → ' .. '[[:تصنيف:' .. nilorR .. ']] (' .. link .. ')' )
else --no #R
table.insert( tlistall, '[[:تصنيف:' .. cat .. ']] (' .. link .. ')' )
end
end
return {
['cat'] = cat,
['catexists'] = exists,
['rtarget'] = nilorR,
['navelement'] = link,
['displaytext'] = disp,
}
end
--Returns a numbered list of all {{تحويل تصنيف}}s followed by catlinkfollowr() -> rtarget().
--For a nav_hyphen() cat, also returns a formatted list of all cats searched for & found, & all loop indices.
--Used by all nav_*().
local function listalllinks()
local nl = '\n# '
local out = ''
if currtitle.nsText == 'تصنيف' then
errors = p.errorclass('The <b><code>|list-all-links=yes</code></b> parameter/utility '..
'should not be saved in category space, only previewed.')
out = p.failedcat(errors, 'Z')
end
local bwd, fwd = '', ''
if tlistallbwd[1] then
bwd = '\n\nbackward search:\n# '..table.concat(tlistallbwd, nl)
end
if tlistallfwd[1] then
fwd = '\n\nforward search:\n# '..table.concat(tlistallfwd, nl)
end
if tlistall[1] then
return out..nl..table.concat(tlistall, nl)..bwd..fwd
else
return out..nl..'No links found!?'..bwd..fwd
end
end
--Returns the difference b/w 2 ints separated by endash|hyphen, nil if error.
--Used by nav_hyphen() only.
local function find_duration( cat )
local from, to = mw.ustring.match(cat, '(%d+)[–-](%d+)')
if from and to then
if to == '00' then return nil end --doesn't follow MOS:DATERANGE
if (#from == 4) and (#to == 2) then --1900-01
to = string.match(from, '(%d%d)%d%d')..to --1900-1901
elseif (#from == 2) and (#to == 4) then -- 01-1902
from = string.match(to, '(%d%d)%d%d')..from --1901-1902
end
return (tonumber(to) - tonumber(from))
end
return 0
end
--Returns the ending of a terminal cat, and sets the appropriate tracking cat, else nil.
--Used by nav_hyphen() only.
local function find_terminaltxt( cat )
local terminaltxt = nil
if mw.ustring.match(cat, '%d+[–-]present$') then
terminaltxt = 'present'
trackcat(14, 'Navseasoncats range ends (present)')
elseif mw.ustring.match(cat, '%d+[–-]$') then
terminaltxt = ''
trackcat(15, 'Navseasoncats range ends (blank, MOS)')
end
return terminaltxt
end
--Returns an unsigned string of the 1-4 digit decade ending in "0", else nil.
--Used by nav_decade() only.
local function sterilizedec( decade )
if decade == nil or decade == '' then
return nil
end
local dec = string.match(decade, '^[-%+]?(%d?%d?%d?0)$') or
string.match(decade, '^[-%+]?(%d?%d?%d?0)%D')
if dec then
return dec
else
--fix 2-4 digit decade
local decade_fixed234 = string.match(decade, '^[-%+]?(%d%d?%d?)%d$') or
string.match(decade, '^[-%+]?(%d%d?%d?)%d%D')
if decade_fixed234 then
return decade_fixed234..'0'
end
--fix 1-digit decade
local decade_fixed1 = string.match(decade, '^[-%+]?(%d)$') or
string.match(decade, '^[-%+]?(%d)%D')
if decade_fixed1 then
return '0'
end
--unfixable
return nil
end
end
--Check for nav_hyphen default gap size + isolatedcat() (not necessarily an error).
--Used by nav_hyphen() only.
local function defaultgapcat( bool )
if bool and nexistingcats == 0 then
--using "nexistingcats > 0" isn't as useful, since the default gap size obviously worked
trackcat(17, 'Navseasoncats default season gap size')
end
end
--12 -> 12th, etc.
--Used by nav_nordinal() & nav_wordinal().
function p.addord( i )
if tonumber(i) then
local s = tostring(i)
local tens = string.match(s, '1%d$')
if tens then return s..'th' end
local ones = string.match(s, '%d$')
if ones == '1' then return s..'st'
elseif ones == '2' then return s..'nd'
elseif ones == '3' then return s..'rd' end
return s..'th'
end
return i
end
--Returns the properly formatted central nav element.
--Expects an integer i, and a catlinkfollowr() table.
--Used by nav_decade() & nav_ordinal() only.
local function navcenter( i, catlink )
if i == 0 then --center nav element
if navborder == true then
return '<b>' .. catlink.displaytext .. '</b>\n'
else
return '<b>' .. catlink.navelement .. '</b>\n'
end
else
return '' .. catlink.navelement .. '\n'
end
end
--Return conditionally aligned stacked navs.
--Used by main only.
local function nav1nav2( nav1, nav2 )
local line = nav1 .. '\n' .. nav2
if er_counts ~= 0 then
line = '#countall: ' .. er_counts .. '\n' .. line
end
return line
--[[if avoidself then
local forcealign = '<div style="display:block !important; max-width: calc(100% - 25em);">'
return forcealign..'\n'..nav1..'\n'..nav2..'\n</div>'
else
return nav1..'\n'..nav2
end]]
end
--[[==========================================================================]]
--[[ Formerly separated templates/modules ]]
--[[==========================================================================]]
--[[==========================={{ nav_hyphen }}=============================]]
local function nav_hyphen( frame, start, hyph, finish, firstpart, lastpart, minseas, maxseas, testgap )
--Expects a PAGENAME of the form "Some sequential 2015–16 example cat", where
-- start = 2015
-- hyph = –
-- finish = 16 (sequential years can be abbreviated, but others should be full year, e.g. "2001–2005")
-- firstpart = Some sequential
-- lastpart = example cat
-- minseas = 1800 ('min' starting season shown; optional; defaults to -9999)
-- maxseas = 2000 ('max' starting season shown; optional; defaults to 9999; 2000 will show 2000-01)
-- testgap = 0 (testcasegap parameter for easier testing; optional)
--sterilize start
if string.match(start or '', '^%d%d?%d?%d?$') == nil then --1-4 digits, AD only
local start_fixed = mw.ustring.match(start or '', '^%s*(%d%d?%d?%d?)%D')
if start_fixed then
start = start_fixed
else
errors = p.errorclass('Function nav_hyphen can\'t recognize the number "'..(start or '')..'" '..
'in the first part of the "season" that was passed to it. '..
'For e.g. "2015–16", "2015" is expected via "|2015|–|16|".')
return p.failedcat(errors, 'H')
end
end
local nstart = tonumber(start)
--en dash check
if hyph ~= '–' then
trackcat(4, 'Navseasoncats range not using en dash') --nav still processable, but track
end
--sterilize finish & check for weird parents
local tgaps = {} --table of gap sizes found b/w terms { [<gap size found>] = 1 }
local ttlens = {} --table of term lengths found w/i terms { [<term length found>] = 1 }
local tirregs = {} --table of ir/regular-term-length cats' "from"s & "to"s found
local regularparent = true
if (finish == -1) or --"Members of the Scottish Parliament 2021–present"
(finish == 0) --"Members of the Scottish Parliament 2021–"
then
regularparent = false
if maxseas == nil or maxseas == '' then
maxseas = start --hide subsequent ranges
end
if finish == -1 then trackcat(14, 'Navseasoncats range ends (present)')
else trackcat(15, 'Navseasoncats range ends (blank, MOS)') end
elseif (start == finish) and
(ttrackingcats[16] ~= '') --nav_year found isolated; check for surrounding hyphenated terms (e.g. UK MPs 1974)
then
trackcat(16, '') --reset for another check later
trackcat(13, 'Navseasoncats range irregular, 0-length')
ttlens[0] = 1 --calc ttlens for std cases below
regularparent = 'isolated'
end
if (string.match(finish or '', '^%d+$') == nil) and
(string.match(finish or '', '^%-%d+$') == nil)
then
local finish_fixed = mw.ustring.match(finish or '', '^%s*(%d%d?%d?%d?)%D')
if finish_fixed then
finish = finish_fixed
else
errors = p.errorclass('Function nav_hyphen can\'t recognize "'..(finish or '')..'" '..
'in the second part of the "season" that was passed to it. '..
'For e.g. "2015–16", "16" is expected via "|2015|–|16|".')
return p.failedcat(errors, 'I')
end
else
if string.len(finish) >= 5 then
errors = p.errorclass('The second part of the season passed to function nav_hyphen should only be four or fewer digits, not "'..(finish or '')..'". '..
'See [[MOS:DATERANGE]] for details.')
return p.failedcat(errors, 'J')
end
end
local nfinish = tonumber(finish)
--save sterilized parent range for easier lookup later
tirregs['from0'] = nstart
tirregs['to0'] = nfinish
--sterilize min/max
local nminseas_default = -9999
local nmaxseas_default = 9999
local nminseas = tonumber(minseas) or nminseas_default --same behavior as nav_year
local nmaxseas = tonumber(maxseas) or nmaxseas_default --same behavior as nav_year
if nminseas > nstart then nminseas = nstart end
if nmaxseas < nstart then nmaxseas = nstart end
local lspace = ' ' --assume a leading space (most common)
local tspace = ' ' --assume a trailing space (most common)
if string.match(firstpart, '%($') then lspace = '' end --DNE for "Madrid city councillors (2007–2011)"-type cats
if string.match(lastpart, '^%)') then tspace = '' end --DNE for "Madrid city councillors (2007–2011)"-type cats
--calculate term length/intRAseason size & finishing year
local term_limit = 10
local t = 1
while t <= term_limit and regularparent == true do
local nish = nstart + t --use switchADBC to flip this sign to work for years BC, if/when the time comes
if (nish == nfinish) or (string.match(nish, '%d?%d$') == finish) then
ttlens[t] = 1
break
end
if t == term_limit then
errors = p.errorclass('Function nav_hyphen can\'t determine a reasonable term length for "'..start..hyph..finish..'".')
return p.failedcat(errors, 'K')
end
t = t + 1
end
--apply MOS:DATERANGE to parent
local lenstart = string.len(start)
local lenfinish = string.len(finish)
if lenstart == 4 and regularparent == true then --"2001–..."
if t == 1 then --"2001–02" & "2001–2002" both allowed
if lenfinish ~= 2 and lenfinish ~= 4 then
errors = p.errorclass('The second part of the season passed to function nav_hyphen should be two or four digits, not "'..finish..'".')
return p.failedcat(errors, 'L')
end
else --"2001–2005" is required for t > 1; track "2001–05"; anything else = error
if lenfinish == 2 then
trackcat(5, 'Navseasoncats range abbreviated (MOS)')
elseif lenfinish ~= 4 then
errors = p.errorclass('The second part of the season passed to function nav_hyphen should be four digits, not "'..finish..'".')
return p.failedcat(errors, 'M')
end
end
if finish == '00' then --full year required regardless of term length
trackcat(5, 'Navseasoncats range abbreviated (MOS)')
end
end
--calculate intERseason gap size
local hgap_default = 0 --assume & start at the most common case: 2001–02 -> 2002–03, etc.
local hgap_limit_reg = 6 --less expensive per-increment (inc x 4)
local hgap_limit_irreg = 6 --more expensive per-increment (inc x 23: inc x (k_bwd + k_fwd) = inc x (12 + 11))
local hgap_success = false
local hgap = hgap_default
while hgap <= hgap_limit_reg and regularparent == true do --verify
local prevseason2 = firstpart..lspace..(nstart-t-hgap)..hyph..string.match(nstart-hgap, '%d?%d$') ..tspace..lastpart
local nextseason2 = firstpart..lspace..(nstart+t+hgap)..hyph..string.match(nstart+2*t+hgap, '%d?%d$')..tspace..lastpart
local prevseason4 = firstpart..lspace..(nstart-t-hgap)..hyph..(nstart-hgap) ..tspace..lastpart
local nextseason4 = firstpart..lspace..(nstart+t+hgap)..hyph..(nstart+2*t+hgap)..tspace..lastpart
if t == 1 then --test abbreviated range first, then full range, to be frugal with expensive functions
if catexists(prevseason2) or --use 'or', in case we're at the edge of the cat structure,
catexists(nextseason2) or --or we hit a "–00"/"–2000" situation on one side
catexists(prevseason4) or
catexists(nextseason4)
then
hgap_success = true
break
end
elseif t > 1 then --test full range first, then abbreviated range, to be frugal with expensive functions
if catexists(prevseason4) or --use 'or', in case we're at the edge of the cat structure,
catexists(nextseason4) or --or we hit a "–00"/"–2000" situation on one side
catexists(prevseason2) or
catexists(nextseason2)
then
hgap_success = true
break
end
end
hgap = hgap + 1
end
if hgap_success == false then
hgap = tonumber(testgap) or hgap_default --tracked via defaultgapcat()
end
--preliminary scan to determine ir/regular spacing of nearby cats;
--to limit expensive function calls, MOS:DATERANGE-violating cats are ignored;
--an irregular-term-length series should follow "YYYY..hyph..YYYY" throughout
if hgap <= hgap_limit_reg then --also to isolate temp vars
--find # of nav-visible ir/regular-term-length cats
local bwanchor = nstart --backward anchor/common year
local fwanchor = bwanchor + t --forward anchor/common year
if regularparent == 'isolated' then
fwanchor = bwanchor
end
local spangreen = '[<span style="color:green">j, g, k = ' --used for/when debugging via list-all-links=yes
local spanblue = '<span style="color:blue">'
local spanred = ' (<span style="color:red">'
local span = '</span>'
local lastg = nil --to check for run-on searches
local lastk = nil --to check for run-on searches
local endfound = false --switch used to stop searching forward
local iirregs = 0 --index of tirregs[] for j < 0, since search starts from parent
local j = -3 --index of tirregs[] for j > 0 & pseudo nav position
while j <= 3 do
if j < 0 then --search backward from parent
local gbreak = false --switch used to break out of g-loop
local g = 0 --gap size
while g <= hgap_limit_irreg do
local k = 0 --term length: 0 = "0-length", 1+ = normal
while k <= term_limit do
local from = bwanchor - k - g
local to = bwanchor - g
local full = mw.text.trim( firstpart..lspace..from..hyph..to..tspace..lastpart )
if k == 0 then
if regularparent ~= 'isolated' then --+restrict to g == 0 if repeating year problems arise
to = '0-length'
full = mw.text.trim( firstpart..lspace..from..tspace..lastpart )
if catlinkfollowr( frame, full ).rtarget ~= nil then --#R followed
table.insert( tlistallbwd, spangreen..j..', '..g..', '..k..span..'] '..full..spanred..'#R ignored'..span..')' )
full, to = '', '' --don't use/follow 0-length cat #Rs from nav_hyphen(); otherwise gets messy
end
end
end
if (k >= 1) or --the normal case; only continue k = 0 if 0-length found
(to == '0-length') --ghetto "continue" (thx Lua) to avoid expensive searches for "UK MPs 1974-1974", etc.
then
table.insert( tlistallbwd, spangreen..j..', '..g..', '..k..span..'] '..full )
if (k == 1) and
(g == 0 or g == 1) and
(catexists(full) == false)
then --allow bare-bones MOS:DATERANGE alternation, in case we're on a 0|1-gap, 1-year term series
local to2 = string.match(to, '%d%d$')
if to2 and to2 ~= '00' then --and not at a century transition (i.e. 1999–2000)
to = to2
full = mw.text.trim( firstpart..lspace..from..hyph..to..tspace..lastpart )
table.insert( tlistallbwd, spangreen..j..', '..g..', '..k..span..'] '..full )
end
end
if catexists(full) then
if to == '0-length' then
trackcat(13, 'Navseasoncats range irregular, 0-length')
end
tlistallbwd[#tlistallbwd] = spanblue..tlistallbwd[#tlistallbwd]..span..' (found)'
ttlens[ find_duration(full) ] = 1
tgaps[g] = 1
iirregs = iirregs + 1
tirregs['from-'..iirregs] = from
tirregs['to-'..iirregs] = to
bwanchor = from --ratchet down
if to ~= '0-length' then
gbreak = true
break
else
g = 0 --soft-reset g, to keep stepping thru k
j = j + 1 --save, but keep searching thru k
if j > 3 then --lest we keep searching & finding 0-length cats ("MEPs for the Republic of Ireland 1973" & down)
gbreak = true
break
end
end
end
end --ghetto "continue"
k = k + 1
lastk = k
end --while k
if gbreak == true then break end
g = g + 1
lastg = g
end --while g
end --if j < 0
if j > 0 and endfound == false then --search forward from parent
local gbreak = false --switch used to break out of g-loop
local g = 0 --gap size
while g <= hgap_limit_irreg do
local k = -2 --term length: -2 = "0-length", -1 = "2020–present", 0 = "2020–", 1+ = normal
while k <= term_limit do
local from = fwanchor + g
local to4 = fwanchor + k + g --override carefully
local to2 = nil --last 2 digits of to4, IIF exists
if k == -1 then to4 = 'present' --see if end-cat exists (present)
elseif k == 0 then to4 = '' end --see if end-cat exists (blank)
local full = mw.text.trim( firstpart..lspace..from..hyph..to4..tspace..lastpart )
if k == -2 then
if regularparent ~= 'isolated' then --+restrict to g == 0 if repeating year problems arise
to4 = '0-length' --see if 0-length cat exists
full = mw.text.trim( firstpart..lspace..from..tspace..lastpart )
if catlinkfollowr( frame, full ).rtarget ~= nil then --#R followed
table.insert( tlistallfwd, spangreen..j..', '..g..', '..k..span..'] '..full..spanred..'#R ignored'..span..')' )
full, to4 = '', '' --don't use/follow 0-length cat #Rs from nav_hyphen(); otherwise gets messy
end
end
end
if (k >= -1) or --only continue k = -2 if 0-length found
(to4 == '0-length') --ghetto "continue" (thx Lua) to avoid expensive searches for "UK MPs 1974-1974", etc.
then
table.insert( tlistallfwd, spangreen..j..', '..g..', '..k..span..'] '..full )
if (k == 1) and
(g == 0 or g == 1) and
(catexists(full) == false)
then --allow bare-bones MOS:DATERANGE alternation, in case we're on a 0|1-gap, 1-year term series
to2 = string.match(to4, '%d%d$')
if to2 and to2 ~= '00' then --and not at a century transition (i.e. 1999–2000)
full = mw.text.trim( firstpart..lspace..from..hyph..to2..tspace..lastpart )
table.insert( tlistallfwd, spangreen..j..', '..g..', '..k..span..'] '..full )
end
end
if catexists(full) then
if to4 == '0-length' then
if rtarget(frame, full) == full then --only use 0-length cats that don't #R
trackcat(13, 'Navseasoncats range irregular, 0-length')
end
end
tirregs['from'..j] = from
tirregs['to'..j] = (to2 or to4)
if (k == -1) or (k == 0) then
endfound = true --tentative
else --k == { -2, > 0 }
tlistallfwd[#tlistallfwd] = spanblue..tlistallfwd[#tlistallfwd]..span..' (found)'
ttlens[ find_duration(full) ] = 1
tgaps[g] = 1
endfound = false
if to4 ~= '0-length' then --k > 0
fwanchor = to4 --ratchet up
gbreak = true
break --only break on k > 0 b/c old end-cat #Rs still exist like "Members of the Scottish Parliament 2011–"
else --k == -2
j = j + 1 --save, but keep searching k's, in case "1974" → "1974-1979"
if j > 3 then --lest we keep searching & finding 0-length cats ("2018 CONCACAF Champions League" & up)
gbreak = true
break
end
end
end
end
end --ghetto "continue"
k = k + 1
lastk = k
end --while k
if gbreak == true then break end
g = g + 1
lastg = g
end --while g
end --if j > 0
if (lastg == (hgap_limit_irreg + 1)) and
(lastk == (term_limit + 1))
then --search exhausted
if j < 0 then j = 0 --bwd search exhausted; continue fwd
elseif j > 0 then break end --fwd search exhausted
end
j = j + 1
end --while j <= 3
end --if hgap <= hgap_limit_reg
--begin navhyphen
local navh = '{| class="toccolours" style="text-align: center; margin: auto;"\n|\n'
local navlist = {}
local terminalcat = false --switch used to hide future cats
local terminaltxt = nil
local i = -3 --nav position
while i <= 3 do
local from = nstart + i*(t+hgap) --the logical, but not necessarily correct, 'from'
if tirregs['from'..i] then from = tonumber(tirregs['from'..i]) end --prefer irregular term table
local from2 = string.match(from, '%d?%d$')
local to = tostring(from+t) --the logical, naive range, but
if tirregs['to'..i] then --prefer irregular term table
to = tirregs['to'..i]
elseif regularparent == false and tirregs and i > 0 then
to = tirregs['to-1'] --special treatment for parent terminal cats, since they have no natural 'to'
end
local to2 = string.match(to, '%d?%d$')
local tofinal = (to2 or '') --assume t=1 and abbreviated 'to' (the most common case)
if t > 1 or --per MOS:DATERANGE (e.g. 1999-2004)
(from2 - (to2 or from2)) > 0 --century transition exception (e.g. 1999–2000)
then
tofinal = (to or '') --default to the MOS-correct format, in case no fallbacks found
end
if to == '0-length' then
tofinal = to
end
--check existance of 4-digit, MOS-correct range, with abbreviation fallback
if tofinal ~= '0-length' then
if t > 1 and string.len(from) == 4 then --e.g. 1999-2004
--determine which link exists (full or abbr)
local full = firstpart..lspace..from..hyph..tofinal..tspace..lastpart
if not catexists(full) then
local abbr = firstpart..lspace..from..hyph..to2..tspace..lastpart
if catexists(abbr) then
tofinal = (to2 or '') --rv to MOS-incorrect format; if full AND abbr DNE, then tofinal is still in its MOS-correct format
end
end
elseif t == 1 then --full-year consecutive ranges are also allowed
local abbr = firstpart..lspace..from..hyph..tofinal..tspace..lastpart --assume tofinal is in abbr format
if not catexists(abbr) and tofinal ~= to then
local full = firstpart..lspace..from..hyph..to..tspace..lastpart
if catexists(full) then
tofinal = (to or '') --if abbr AND full DNE, then tofinal is still in its abbr format (unless it's a century transition)
end end end end
--populate navh
if i ~= 0 then --left/right navh
local orig = firstpart..lspace..from..hyph..tofinal..tspace..lastpart
local disp = from..hyph..tofinal
if tofinal == '0-length' then
orig = firstpart..lspace..from..tspace..lastpart
disp = from
end
local catlink = catlinkfollowr(frame, orig, disp, true) --force terminal cat display
if terminalcat == false then
terminaltxt = find_terminaltxt( disp ) --also sets tracking cats
terminalcat = (terminaltxt ~= nil)
end
if catlink.rtarget and avoidself then --a {{تحويل تصنيف}} was followed, figure out why
--determine new term length & gap size
ttlens[ find_duration( catlink.rtarget ) ] = 1
if i > -3 then
local lastto = tirregs['to'..(i-1)]
if lastto == nil then
local lastfrom = nstart + (i-1)*(t+hgap)
lastto = lastfrom+t --use last logical 'from' to calc lastto
end
if lastto then
local gapcat = lastto..'-'..from --dummy cat to calc with
local gap = find_duration(gapcat) or -1 --in case of nil,
tgaps[ gap ] = 1 --tgaps[-1] is ignored
end
end
--display/tracking handling
local base_regex = '%d+[–-]%d+'
local origbase = mw.ustring.gsub(orig, base_regex, '')
local rtarbase, rtarbase_success = mw.ustring.gsub(catlink.rtarget, base_regex, '')
if rtarbase_success == 0 then
local base_regex_lax = '%d%d%d%d' --in case rtarget is a year cat
rtarbase, rtarbase_success = mw.ustring.gsub(catlink.rtarget, base_regex_lax, '')
end
local terminal_regex = '%d+[–-]'..(terminaltxt or '')..'$' --more manual ORs bc Lua regex sux
if mw.ustring.match(orig, terminal_regex) then
origbase = mw.ustring.gsub(orig, terminal_regex, '')
end
if mw.ustring.match(catlink.rtarget, terminal_regex) then
--finagle/overload terminalcat type to set nmaxseas on 1st occurence only
if terminalcat == false then terminalcat = 1 end
local dummy = find_terminaltxt( catlink.rtarget ) --also sets tracking cats
rtarbase = mw.ustring.gsub(catlink.rtarget, terminal_regex, '')
end
origbase = mw.text.trim(origbase)
rtarbase = mw.text.trim(rtarbase)
if origbase ~= rtarbase then
trackcat(6, 'Navseasoncats range redirected (base change)')
elseif terminalcat == 1 then
trackcat(8, 'Navseasoncats range redirected (end)')
else --origbase == rtarbase
local all4s_regex = '%d%d%d%d[–-]%d%d%d%d'
local orig_all4s = mw.ustring.match(orig, all4s_regex)
local rtar_all4s = mw.ustring.match(catlink.rtarget, all4s_regex)
if orig_all4s and rtar_all4s then
trackcat(10, 'Navseasoncats range redirected (other)')
else
local year_regex1 = '%d%d%d%d$'
local year_regex2 = '%d%d%d%d[%s%)]'
local year_rtar = mw.ustring.match(catlink.rtarget, year_regex1) or
mw.ustring.match(catlink.rtarget, year_regex2)
if orig_all4s and year_rtar then
trackcat(7, 'Navseasoncats range redirected (var change)')
else
trackcat(9, 'Navseasoncats range redirected (MOS)')
end
end
end
end
if terminalcat then --true or 1
if type(terminalcat) ~= 'boolean' then nmaxseas = from end --only want to do this once
terminalcat = true --done finagling/overloading
end
if (from >= 0) and (nminseas <= from) and (from <= nmaxseas) then
table.insert(navlist, catlink.navelement)
if terminalcat then nmaxseas = nminseas_default end --prevent display of future ranges
else
local hidden = '<span style="visibility:hidden">'..disp..'</span>'
table.insert(navlist, hidden)
if listall then
tlistall[#tlistall] = tlistall[#tlistall]..' ('..hidden..')'
end
end
else --center navh
if finish == -1 then finish = 'present'
elseif finish == 0 then finish = '<span style="visibility:hidden">'..start..'</span>' end
local disp = start..hyph..finish
if regularparent == 'isolated' then disp = start end
table.insert(navlist, '<b>'..disp..'</b>')
end
i = i + 1
end
-- add the list
navh = navh..horizontal(navlist)..'\n'
--tracking cats & finalize
if avoidself then
local igaps = 0 --# of diff gap sizes > 0 found
local itlens = 0 --# of diff term lengths found
for s = 1, hgap_limit_reg do --must loop; #tgaps, #ttlens unreliable
igaps = igaps + (tgaps[s] or 0)
end
for s = 0, term_limit do
itlens = itlens + (ttlens[s] or 0)
end
if igaps > 0 then trackcat(11, 'Navseasoncats range gaps') end
if itlens > 1 and ttrackingcats[13] == '' then --avoid duplication in "Navseasoncats range irregular, 0-length"
trackcat(12, 'Navseasoncats range irregular')
end
end
isolatedcat()
defaultgapcat(not hgap_success)
if listall then
return listalllinks()
else
return navh..'|}'
end
end
--[[=========================={{ nav_tvseason }}============================]]
local function nav_tvseason( frame, firstpart, tv, lastpart, maximumtv )
--Expects a PAGENAME of the form "Futurama (season 1) episodes", where
-- firstpart = Futurama (season
-- tv = 1
-- lastpart = ) episodes
-- maximumtv = 7 ('max' tv season parameter; optional; defaults to 9999)
tv = tonumber(tv)
if tv == nil then
errors = p.errorclass('Function nav_tvseason can\'t recognize the TV season number sent to its 2nd parameter.')
return p.failedcat(errors, 'T')
end
local maxtv = tonumber(maximumtv) or 9999 --allow +/- qualifier
if maxtv < tv then maxtv = tv end --input error; maxtv should be >= parent
--begin navtvseason
local navt = '{| class="toccolours" style="text-align: center; margin: auto;"\n|\n'
local navlist = {}
local i = -5 --nav position
while i <= 5 do
local t = tv + i
if i ~= 0 then --left/right navt
local catlink = catlinkfollowr( frame, firstpart..' '..t..lastpart, t )
if (t >= 1 and t <= maxtv) then --hardcode mintv
if catlink.rtarget then --a {{تحويل تصنيف}} was followed
trackcat(25, 'Navseasoncats TV season redirected')
end
table.insert(navlist, catlink.navelement)
else
local hidden = '<span style="visibility:hidden">'..'0'..'</span>' --'0' to maintain dot spacing
table.insert(navlist, hidden)
if listall then
tlistall[#tlistall] = tlistall[#tlistall]..' ('..hidden..')'
end
end
else --center navt
table.insert(navlist, '<b>'..tv..'</b>')
end
i = i + 1
end
-- add the list
navt = navt..horizontal(navlist)..'\n'
isolatedcat()
if listall then
return listalllinks()
else
return navt..'|}'
end
end
--[[==========================={{ nav_decade }}=============================]]
local function nav_decade( frame, firstpart, decade, lastpart, mindecade, maxdecade )
--Expects a PAGENAME of the form "Some sequential 2000 example cat", where
-- firstpart = Some sequential
-- decade = 2000
-- lastpart = example cat
-- mindecade = 1800 ('min' decade parameter; optional; defaults to -9999)
-- maxdecade = 2020 ('max' decade parameter; optional; defaults to 9999)
--sterilize dec
local dec = sterilizedec(decade)
if dec == nil then
errors = p.errorclass('Function nav_decade was sent "'..(decade or '')..'" as its 2nd parameter, '..
'but expects a 1 to 4-digit year ending in "0".')
return p.failedcat(errors, 'D')
end
local ndec = tonumber(dec)
--sterilize mindecade & determine AD/BC
local mindefault = '-9999'
local mindec = sterilizedec(mindecade) --returns a tostring(unsigned int), or nil
if mindec then
if string.match(mindecade, '-%d') or
string.match(mindecade, 'BC')
then
mindec = '-'..mindec --better +/-0 behavior with strings (0-initialized int == "-0" string...)
end
elseif mindec == nil and mindecade and mindecade ~= '' then
errors = p.errorclass('Function nav_decade was sent "'..(mindecade or '')..'" as its 4th parameter, '..
'but expects a 1 to 4-digit year ending in "0", the earliest decade to be shown.')
return p.failedcat(errors, 'E')
else --mindec == nil
mindec = mindefault --tonumber() later, after error checks
end
--sterilize maxdecade & determine AD/BC
local maxdefault = '9999'
local maxdec = sterilizedec(maxdecade) --returns a tostring(unsigned int), or nil + error
if maxdec then
if string.match(maxdecade, '-%d') or
string.match(maxdecade, 'BC')
then --better +/-0 behavior with strings (0-initialized int == "-0" string...),
maxdec = '-'..maxdec --but a "-0" string -> tonumber() -> tostring() = "-0",
end --and a "0" string -> tonumber() -> tostring() = "0"
elseif maxdec == nil and maxdecade and maxdecade ~= '' then
errors = p.errorclass('Function nav_decade was sent "'..(maxdecade or '')..'" as its 5th parameter, '..
'but expects a 1 to 4-digit year ending in "0", the highest decade to be shown.')
return p.failedcat(errors, 'F')
else --maxdec == nil
maxdec = maxdefault
end
local tspace = ' ' --assume trailing space for "1950s in X"-type cats
if string.match(lastpart, '^-') then tspace = '' end --DNE for "1970s-related"-type cats
--AD/BC switches & vars
-- local parentBC = string.match(lastpart, '^BC') --following the "0s BC" convention for all years BC
local parentBC = string.match(lastpart, '^%s*(ق%sم)')
lastpart = mw.ustring.gsub(lastpart, '^BC%s*', '') --handle BC separately; AD never used
--TODO?: handle BCE, but only if it exists in the wild
lastpart = mw.ustring.gsub(lastpart, '^ق م%s*', '')
local dec0to40AD = (ndec >= 0 and ndec <= 40 and not parentBC) --special behavior in this range
local switchADBC = 1 -- 1=AD parent
if parentBC then switchADBC = -1 end -- -1=BC parent; possibly adjusted later
local BCdisp = ''
local D = -math.huge --secondary switch & iterator for AD/BC transition
--check non-default min/max more carefully
if mindec ~= mindefault then
if tonumber(mindec) > ndec*switchADBC then
mindec = tostring(ndec*switchADBC) --input error; mindec should be <= parent
end
end
if maxdec ~= maxdefault then
if tonumber(maxdec) < ndec*switchADBC then
maxdec = tostring(ndec*switchADBC) --input error; maxdec should be >= parent
end
end
local nmindec = tonumber(mindec) --similar behavior to nav_year & nav_nordinal
local nmaxdec = tonumber(maxdec) --similar behavior to nav_nordinal
--begin navdecade
local bnb = '' --border/no border
if navborder == false then --for Navseasoncats year and decade
bnb = ' border-style: none; background-color: transparent;'
end
local navd = '{| class="toccolours" style="text-align: center; margin: auto;'..bnb..'"\n|\n'
local navlist = {}
local i = -50 --nav position x 10
while i <= 50 do
local d = ndec + i*switchADBC
local BC = ''
BCdisp = ''
if dec0to40AD then
if D < -10 then
d = math.abs(d + 10) --b/c 2 "0s" decades exist: "0s BC" & "0s" (AD)
-- BC = 'BC '
BC = ' ق م '
if d == 0 then
D = -10 --track 1st d = 0 use (BC)
end
elseif D >= -10 then
D = D + 10 --now iterate from 0s AD
d = D --2nd d = 0 use
end
elseif parentBC then
if switchADBC == -1 then --parentBC looking at the BC side (the common case)
BC = ' ق م '
-- BC = 'BC '
if d == 0 then --prepare to switch to the AD side on the next iteration
switchADBC = 1 --1st d = 0 use (BC)
D = -10 --prep
end
elseif switchADBC == 1 then --switched to the AD side
D = D + 10 --now iterate from 0s AD
d = D --2nd d = 0 use (on first use)
end
end
if BC ~= '' and ndec <= 50 then
--BCdisp = ' BC' --show BC for all BC decades whenever a "0s" is displayed on the nav
BCdisp = ' ق م '
end
--determine target cat
-- local disp = d .. 's' .. BCdisp
local disp = 'عقد ' .. d .. BCdisp
-- local link1 = firstpart .. ' ' .. d .. 's' .. tspace .. BC .. lastpart
local link1 = firstpart .. ' ' .. d .. '' .. tspace .. BC .. lastpart
local catlink = catlinkfollowr( frame, link1, disp )
if catlink.rtarget then --a {{تحويل تصنيف}} was followed
trackcat(18, 'Navseasoncats decade redirected')
end
--populate left/right navd
local shown = navcenter(i, catlink)
local hidden = '<span style="visibility:hidden">'..disp..'</span>'
local dsign = d --use d for display & dsign for logic
if BC ~= '' then dsign = -dsign end
if (nmindec <= dsign) and (dsign <= nmaxdec) then
if dsign == 0 and (nmindec == 0 or nmaxdec == 0) then --distinguish b/w -0 (BC) & 0 (AD)
--"zoom in" on +/- 0 and turn dsign/min/max temporarily into +/- 1 for easier processing
local zsign, zmin, zmax = 1, nmindec, nmaxdec
if BC ~= '' then zsign = -1 end
if mindec == '-0' then zmin = -1
elseif mindec == '0' then zmin = 1 end
if maxdec == '-0' then zmax = -1
elseif maxdec == '0' then zmax = 1 end
if (zmin <= zsign) and (zsign <= zmax) then
table.insert(navlist, shown)
hidden = nil
else
table.insert(navlist, hidden)
end
else
table.insert(navlist, shown)--the common case
hidden = nil
end
else
table.insert(navlist, hidden)
end
if listall and hidden then
tlistall[#tlistall] = tlistall[#tlistall]..' ('..hidden..')'
end
i = i + 10
end
-- add the list
navd = navd..horizontal(navlist)..'\n'
isolatedcat()
if listall then
return listalllinks()
else
return navd..'|}'
end
end
--[[============================{{ nav_year }}==============================]]
local function nav_year( frame, firstpart, year, lastpart, minimumyear, maximumyear )
--Expects a PAGENAME of the form "Some sequential 1760 example cat", where
-- firstpart = Some sequential
-- year = 1760
-- lastpart = example cat
-- minimumyear = 1758 ('min' year parameter; optional)
-- maximumyear = 1800 ('max' year parameter; optional)
local minyear_default = -9999
local maxyear_default = 9999
year = tonumber(year) or tonumber(mw.ustring.match(year or "", "^%s*(%d*)"))
local minyear = tonumber(string.match(minimumyear or "", "-?%d+")) or minyear_default
local maxyear = tonumber(string.match(maximumyear or "", "-?%d+")) or maxyear_default
if string.match(minimumyear or "", "BC") then
minyear = -math.abs(minyear)
end
if string.match(maximumyear or "", "BC") then
maxyear = -math.abs(maxyear)
end
if year == nil then
errors = p.errorclass("Function nav_year can't recognize the year sent to its 2nd parameter.")
return p.failedcat(errors, "Y")
end
local space = " "
-- if string.match(firstpart, '[%-VW]$') then space = '' end
local parentBC = string.match(lastpart, "^%s*(ق%sم)")
lastpart = mw.ustring.gsub(lastpart, "^%s*ق%s*م%s*", "")
local BCe = parentBC or "ق م"
local year1to15AD = (year >= 1 and year <= 15 and not parentBC)
local switchADBC = 1
if parentBC then
switchADBC = -1
end
mw.log("switchADBC:" .. switchADBC)
local Y = 0
if minyear > year * switchADBC then
minyear = year * switchADBC
end
if maxyear < year * switchADBC then
maxyear = year * switchADBC
end
local ygapdefault = 1
local ygap = ygapdefault
mw.log("firstpart '" .. firstpart .. "'")
if
mw.ustring.match(firstpart, "%s*كأس%s*العالم%s*") or
mw.ustring.match(firstpart, "%s*الأولمبية%s*") or
mw.ustring.match(firstpart, "%s*البارالمبية%s*") or
mw.ustring.match(firstpart, "%s*الألعاب%s*الآسيوية%s*") or
mw.ustring.match(firstpart, "%s*الرئاسة%s*الأمريكية%s*") or
mw.ustring.match(firstpart, "%s*الألعاب%s*الأفريقية%s*") or
mw.ustring.match(firstpart, "%s*الألعاب%s*الأوروبية%s*") or
mw.ustring.match(firstpart, "%s*أمريكا%s*الوسطى%s*والكاريبي%s*") or
mw.ustring.match(firstpart, "%s*ألعاب%s*الكومنولث%s*") or
mw.ustring.match(firstpart, "%s*الألعاب%s*الأمريكية%s*")
then
ygap = 4
end
lastpart = " " .. lastpart
if string.match(firstpart, "انتخابات الرئاسة") then
local ygap1, ygap2 = ygapdefault, ygapdefault
local ygap1_success, ygap2_success = false, false
local prevseason = nil
while ygap1 <= 5 do
prevseason = firstpart .. space .. (year - ygap1) .. lastpart
if mw.title.new(prevseason, "تصنيف").exists then
ygap1_success = true
break
end
ygap1 = ygap1 + 1
end
local nextseason = nil
while ygap2 <= 5 do
nextseason = firstpart .. space .. (year + ygap2) .. lastpart
if mw.title.new(nextseason, "تصنيف").exists then
ygap2_success = true
break
end
ygap2 = ygap2 + 1
end
if ygap1_success and ygap2_success then
if ygap1 == ygap2 then
ygap = ygap1
end
elseif ygap1_success then
ygap = ygap1
elseif ygap2_success then
ygap = ygap2
end
end
local ynogaps = {}
local skipgaps_limit = 25
if skipgaps then
if minyear == minyear_default then
minyear = 0
end
if (year > 70) or (minyear >= 0 and not parentBC) then
local yskipped = {}
local cat, found, Yeary
local Year = year
local i = 1
while i <= 5 do
local y = 1
while y <= skipgaps_limit do
found = false
Yeary = Year + y
if yskipped[Yeary] == nil then
yskipped[Yeary] = Yeary
cat = firstpart .. space .. Yeary .. " " .. lastpart
found = mw.title.new(cat, "تصنيف").exists
if found then
break
end
end
y = y + 1
end
if found then
Year = Yeary
else
Year = Year + 1
end
ynogaps[i] = Year
i = i + 1
end
ynogaps[0] = year
Year = year
i = -1
while i >= -5 do
local y = -1
while y >= -skipgaps_limit do
found = false
Yeary = Year + y
if yskipped[Yeary] == nil then
yskipped[Yeary] = Yeary
cat = firstpart .. space .. Yeary .. " " .. lastpart
found = mw.title.new(cat, "تصنيف").exists
if found then
break
end
end
y = y - 1
end
if found then
Year = Yeary
else
Year = Year - 1
end
ynogaps[i] = Year
i = i - 1
end
else
skipgaps = false
end
end
local navy = '{| class="toccolours hlist" style="text-align: center; margin: auto;"\n' .. "|\n"
local y
local i = -5
while i <= 5 do
if skipgaps then
y = ynogaps[i]
else
y = year + i * ygap * switchADBC
end
mw.log("y: (" .. y .. ")")
local BCdisp = ""
if i ~= 0 then
local AD = ""
local BC = ""
if year1to15AD then
mw.log("year1to15AD, i: (" .. i .. ")")
if year >= 11 then
if y <= 10 then
AD = " ق م "
end
elseif year >= 1 then
if y <= 0 then
BC = BCe .. " "
y = math.abs(y - 1)
elseif y >= 1 and y <= 10 then
AD = " ق م "
end
end
elseif parentBC then
mw.log("parentBC, i: (" .. i .. ")")
if switchADBC == -1 then
if y >= 1 then
BC = BCe .. " "
elseif y == 0 then
switchADBC = 1
end
end
if switchADBC == 1 then
Y = Y + 1
y = Y
AD = " ق م "
end
end
if BC ~= "" and year <= 5 then
BCdisp = " " .. BCe
end
local ysign = y
local disp = y .. " " .. BCdisp
if BC ~= "" then
ysign = -ysign
end
local link1 = firstpart .. space .. y .. " " .. BC .. lastpart
-- ---------------------------
-- ---------------------------
if (minyear <= ysign) and (ysign <= maxyear) then
local catlinkAD = catlinkfollowr(frame, link1, disp)
local catlink = catlinkAD
--[[if AD ~= "" then
local catlinkNoAD = catlinkfollowr(frame, link1, disp)
if catlinkNoAD.catexists == true then
catlink = catlinkNoAD
elseif listall then
tlistall[#tlistall] = tlistall[#tlistall] .. " (tried; not displayed)"
end
end]]
-- ---------------------------
local yHyph_4 = y .. "–" .. (y + 1)
local link2 = firstpart .. space .. " " .. yHyph_4 .. BC .. lastpart
-- ---------------------------
if (AD .. BC == "") and (catlink.catexists == false) and (y >= 1000) then
-- ---------------------------
local done = false
-- ---------------------------
if link2 ~= link1 then
local catlinkHyph_4 = catlinkfollowr(frame, link2, yHyph_4)
-- ---------------------------
if catlinkHyph_4.catexists and catlinkHyph_4.rtarget == nil then
catlink = catlinkHyph_4
trackcat(27, "Navseasoncats year and range")
done = true
else
if listall and link2 ~= link1 then
tlistall[#tlistall] = tlistall[#tlistall] .. " (tried; not displayed)"
end
end
-- ---------------------------
end
-- ---------------------------
if not done then
local yHyph_2 = y .. "–" .. string.match(y + 1, "%d%d$")
local link3 = firstpart .. space .. " " .. yHyph_2 .. BC .. lastpart
-- ---------------------------
if link3 ~= link1 and link3 ~= link2 then
local catlinkHyph_2 = catlinkfollowr(frame, link3, yHyph_2)
-- ---------------------------
if catlinkHyph_2.catexists and catlinkHyph_2.rtarget == nil then
catlink = catlinkHyph_2
trackcat(27, 'Navseasoncats year and range')
elseif listall then
tlistall[#tlistall] = tlistall[#tlistall] .. " (tried; not displayed)"
end
end
end
end
-- ---------------------------
if catlink.rtarget then
local r = catlink.rtarget
local c = catlink.cat
local regex_year = "%d%d%d%d[–-]?%d?%d?%d?%d?"
local regex_num = "%d+"
local regex_final = nil
if string.match(r, regex_year) and string.match(c, regex_year) then
regex_final = regex_year
elseif string.match(r, regex_num) and string.match(c, regex_num) then
regex_final = regex_num
end
if regex_final then
local r_base = mw.ustring.gsub(r, regex_final, "")
local c_base = mw.ustring.gsub(c, regex_final, "")
if r_base ~= c_base then
trackcat(19, 'Navseasoncats year redirected (base change)') --acceptable #R target
else
trackcat(21, 'Navseasoncats year redirected (other)') --exceptions go here
end
else
trackcat(20, 'Navseasoncats year redirected (var change)') --e.g. "V2 engines" to "V-twin engines"
end
end
navy = navy .. "*" .. catlink.navelement .. "\n"
else
local hidden = '<span style="visibility:hidden">' .. disp .. "</span>"
navy = navy .. "*" .. hidden .. "\n"
if listall then
-- local dummy = catlinkfollowr(frame, link, disp)
tlistall[#tlistall] = tlistall[#tlistall] .. " (" .. hidden .. ")"
end
end
else
-- code code
-- code code
-- code code
-- code code
-- code code
if parentBC then
BCdisp = " " .. BCe
end
local line = year .. BCdisp
navy = navy .. "*<b>" .. line .. "</b>\n"
end
i = i + 1
end
isolatedcat()
if listall then
return listalllinks()
else
return navy .. "|}"
end
end
--[[==========================={{ nav_roman }}==============================]]
local function nav_roman( frame, firstpart, roman, lastpart, minimumrom, maximumrom )
local toarabic = require('Module:ConvertNumeric/en').roman_to_numeral
local toroman = require('Module:Roman').main
--sterilize/convert rom/num
local num = tonumber(toarabic(roman))
local rom = toroman({ [1] = num })
if num == nil or rom == nil then --out of range or some other error
errors = p.errorclass('Function nav_roman can\'t recognize one or more of "'..(num or 'nil')..'" & "'..
(rom or 'nil')..'" in category "'..firstpart..' '..roman..' '..lastpart..'".')
return p.failedcat(errors, 'R')
end
--sterilize min/max
local minrom = tonumber(minimumrom or '') or tonumber(toarabic(minimumrom or ''))
local maxrom = tonumber(maximumrom or '') or tonumber(toarabic(maximumrom or ''))
if minrom < 1 then minrom = 1 end --toarabic() returns -1 on error
if maxrom < 1 then maxrom = 9999 end --toarabic() returns -1 on error
if minrom > num then minrom = num end
if maxrom < num then maxrom = num end
--begin navroman
local navr = '{| class="toccolours" style="text-align: center; margin: auto;"\n|\n'
local navlist = {}
local i = -5 --nav position
while i <= 5 do
local n = num + i
if n >= 1 then
local r = toroman({ [1] = n })
if i ~= 0 then --left/right navr
local catlink = catlinkfollowr( frame, firstpart..' '..r..' '..lastpart, r )
if minrom <= n and n <= maxrom then
if catlink.rtarget then --a {{تحويل تصنيف}} was followed
trackcat(22, 'Navseasoncats roman numeral redirected')
end
table.insert(navlist, catlink.navelement)
else
local hidden = '<span style="visibility:hidden">'..r..'</span>'
table.insert(navlist, hidden)
if listall then
tlistall[#tlistall] = tlistall[#tlistall]..' ('..hidden..')'
end
end
else --center navr
table.insert(navlist, '<b>'..r..'</b>')
end
else
table.insert(navlist, '<span style="visibility:hidden">I</span>')
end
i = i + 1
end
-- add the list
navr = navr..horizontal(navlist)..'\n'
isolatedcat()
if listall then
return listalllinks()
else
return navr..'|}'
end
end
--[[=========================={{ nav_nordinal }}============================]]
local function nav_nordinal( frame, firstpart, ord, lastpart, minimumord, maximumord )
local nord = tonumber(ord)
local minord = tonumber(string.match(minimumord or '', '(-?%d+)[snrt]?[tdh]?')) or -9999 --allow full ord & +/- qualifier
local maxord = tonumber(string.match(maximumord or '', '(-?%d+)[snrt]?[tdh]?')) or 9999 --allow full ord & +/- qualifier
if string.match(minimumord or '', 'BC') then minord = -math.abs(minord) end --allow BC qualifier (AD otherwise assumed)
if string.match(maximumord or '', 'BC') then maxord = -math.abs(maxord) end --allow BC qualifier (AD otherwise assumed)
-- local temporal = string.match(lastpart, 'century') or string.match(lastpart, 'millennium')
local temporal = string.match(firstpart, 'القرن') or -- century
string.match(firstpart, 'الألفية') -- millennium
mw.log('nav_nordinal firstpart:' .. firstpart)
local tspace = ' ' --assume a trailing space after ordinal
if string.match(lastpart, '^-') then tspace = '' end --DNE for "19th-century"-type cats
--AD/BC switches & vars
local ordBCElastparts = { --needed for parent = AD 1-5, when the BC/E format is unknown
--lists the lastpart of valid BCE cats
--"BCE" removed to match both AD & BCE cats; easier & faster than multiple string.match()s
['-century Hebrew people'] = 'BCE', --WP:CFD/Log/2016 June 21#Category:11th-century BC Hebrew people
['-century Jews'] = 'BCE', --co-nominated
['-century Judaism'] = 'BCE', --co-nominated
['-century rabbis'] = 'BCE', --co-nominated
['-century High Priests of Israel'] = 'BCE',
}
-- local parentBC = mw.ustring.match(lastpart, '%s(BCE?)') --"1st-century BC" format
local parentBC = mw.ustring.match(lastpart, '^%s*(ق%sم)')
-- local lastpartNoBC = mw.ustring.gsub(lastpart, '%sBCE?', '') --easier than splitting lastpart up in 2; AD never used
local lastpartNoBC = mw.ustring.gsub(lastpart, '^%s*ق%s*م%s*' , '')
-- local BCe = parentBC or ordBCElastparts[lastpartNoBC] or 'BC' --"BC" default
local BCe = parentBC or 'ق م' --"BC" default
local switchADBC = 1 -- 1=AD parent
if parentBC then switchADBC = -1 end -- -1=BC parent; possibly adjusted later
local O = 0 --secondary iterator for AD-on-a-BC-parent
if not temporal and minord < 1 then minord = 1 end --nothing before "1st parliament", etc.
if minord > nord*switchADBC then minord = nord*switchADBC end --input error; minord should be <= parent
if maxord < nord*switchADBC then maxord = nord*switchADBC end --input error; maxord should be >= parent
--begin navnordinal
local bnb = '' --border/no border
if navborder == false then --for Navseasoncats decade and century
bnb = ' border-style: none; background-color: transparent;'
end
local navo = '{| class="toccolours" style="text-align: center; margin: auto;'..bnb..'"\n|\n'
firstpart = ' ' .. firstpart .. ' '
local navlist = {}
local i = -5 --nav position
while i <= 5 do
local o = nord + i*switchADBC
local BC = ''
local BCdisp = ''
if parentBC then
if switchADBC == -1 then --parentBC looking at the BC side
if o >= 1 then --the common case
BC = ' '..BCe
elseif o == 0 then --switch to the AD side
BC = ''
switchADBC = 1
end
end
if switchADBC == 1 then --displayed o is now in the AD regime
O = O + 1 --skip o = 0 (DNE)
o = O --easiest solution: start another iterator for these AD o's displayed on a BC year parent
end
elseif o <= 0 then --parentAD looking at BC side
BC = ' '..BCe
o = math.abs(o - 1) --skip o = 0 (DNE)
end
if BC ~= '' and nord <= 5 then --only show 'BC' for parent ords <= 5: saves room, easier to read,
BCdisp = ' '..BCe --and 6 is the first/last nav ord that doesn't need a disambiguator;
end --the center/parent ord will always show BC, so no need to show it another 10x
--populate left/right navo
local oth = ' ' .. o --p.addord(o)
local osign = o --use o for display & osign for logic
if BC ~= '' then osign = -osign end
local hidden = '<span style="visibility:hidden">'..oth..'</span>'
if temporal then --e.g. "3rd-century BC"
local lastpart = lastpartNoBC --lest we recursively add multiple "BC"s
if BC ~= '' then
lastpart = string.gsub(lastpart, temporal, temporal..BC) --replace BC if needed
end
-- local catlink = catlinkfollowr( frame, firstpart .. ' ' .. oth .. tspace .. lastpart, oth .. BCdisp )
local catlink = catlinkfollowr( frame, firstpart .. o .. ' ' .. BCdisp .. ' ' .. tspace .. lastpart , temporal .. ' ' .. oth .. BCdisp )
if (minord <= osign) and (osign <= maxord) then
if catlink.rtarget then --a {{تحويل تصنيف}} was followed
trackcat(23, 'Navseasoncats nordinal redirected')
end
table.insert(navlist, navcenter(i, catlink))
else
table.insert(navlist, hidden)
if listall then
tlistall[#tlistall] = tlistall[#tlistall]..' ('..hidden..')'
end
end
elseif BC == '' and minord <= osign and osign <= maxord then --e.g. >= "1st parliament"
-- local catlink = catlinkfollowr( frame, firstpart .. ' ' .. oth .. tspace .. lastpart, oth )
local catlink = catlinkfollowr( frame, firstpart .. o .. ' ' .. BCdisp .. ' ' .. tspace .. lastpart, temporal .. ' ' .. oth )
if catlink.rtarget then --a {{تحويل تصنيف}} was followed
trackcat(23, 'Navseasoncats nordinal redirected')
end
table.insert(navlist, navcenter(i, catlink))
else --either out-of-range (hide), or non-temporal + BC = something might be wrong (2nd X parliament BC?); handle exceptions if/as they arise
table.insert(navlist, hidden)
end
i = i + 1
end
navo = navo..horizontal(navlist)..'\n'
isolatedcat()
if listall then
return listalllinks()
else
return navo..'|}'
end
end
--[[========================={{ nav_wordinal }}=============================]]
local function nav_wordinal( frame, firstpart, word, lastpart, minimumword, maximumword, ordinal, frame )
--Module:ConvertNumeric.spell_number2() args:
-- ordinal == true : 'second' is output instead of 'two'
-- ordinal == false: 'two' is output instead of 'second'
local ord2eng = require('Module:ConvertNumeric/en').numeral_to_english
local eng2ord = require('Module:ConvertNumeric/en').english_to_ordinal
local th = 'th'
if not ordinal then
th = ''
eng2ord = require('Module:ConvertNumeric/en').english_to_numeral
end
local capitalize = nil ~= string.match(word, '^%u') --determine capitalization
local nord = eng2ord(string.lower(word)) --operate on/with lowercase, and restore any capitalization later
local lspace = ' ' --assume a leading space (most common)
local tspace = ' ' --assume a trailing space (most common)
if string.match(firstpart, '[%-%(]$') then lspace = '' end --DNE for "Straight-eight engines"-type cats
if string.match(lastpart, '^[%-%)]' ) then tspace = '' end --DNE for "Nine-cylinder engines"-type cats
--sterilize min/max
local minword = 1
local maxword = 99
if minimumword then
local num = tonumber(minimumword)
if num and 0 < num and num < maxword then
minword = num
else
local ord = eng2ord(minimumword)
if 0 < ord and ord < maxword then
minword = ord
end
end
end
if maximumword then
local num = tonumber(maximumword)
if num and 0 < num and num < maxword then
maxword = num
else
local ord = eng2ord(maximumword)
if 0 < ord and ord < maxword then
maxword = ord
end
end
end
if minword > nord then minword = nord end
if maxword < nord then maxword = nord end
--begin navwordinal
local navw = '{| class="toccolours" style="text-align: center; margin: auto;"\n|\n'
local navlist = {}
local i = -5 --nav position
while i <= 5 do
local n = nord + i
if n >= 1 then
-- local nth = p.addord(n)
local nth = " القرن " .. n
if not ordinal then nth = n end
if i ~= 0 then --left/right navw
local w = ord2eng{ num = n, ordinal = ordinal, capitalize = capitalize }
local catlink = catlinkfollowr( frame, firstpart..lspace..w..tspace..lastpart, nth )
if minword <= n and n <= maxword then
if catlink.rtarget then --a {{تحويل تصنيف}} was followed
trackcat(24, 'Navseasoncats wordinal redirected')
end
table.insert(navlist, catlink.navelement)
else
local hidden = '<span style="visibility:hidden">'..nth..'</span>'
table.insert(navlist, hidden)
if listall then
tlistall[#tlistall] = tlistall[#tlistall]..' ('..hidden..')'
end
end
else --center navw
table.insert(navlist, '<b>'..nth..'</b>')
end
else
table.insert(navlist, '<span style="visibility:hidden">'..'0'..th..'</span>')
end
i = i + 1
end
-- Add the list
navw = navw..horizontal(navlist)..'\n'
isolatedcat()
if listall then
return listalllinks()
else
return navw..'|}'
end
end
--[[==========================={{ find_var }}===============================]]
local function find_var( pn )
--Extracts the variable text (e.g. 2015, 2015–16, 2000s, 3rd, III, etc.) from a string,
--and returns { ['vtype'] = <'year'|'season'|etc.>, <v> = <2015|2015–16|etc.> }
local pagename = currtitle.text
if pn and pn ~= '' then
pagename = pn
end
local cpagename = 'تصنيف:' .. pagename --limited-Lua-regex workaround
local d_season = mw.ustring.match(cpagename, ':عقد (%d+).+%(%d+[–-]%d+%)') --i.e. [[Category:1760s in the Province of Quebec (1763–1791)]]
local y_season = mw.ustring.match(cpagename, ':(%d+) .+%(%d+[–-]%d+%)') --i.e. "1763 establishments in the Province of Quebec (1763–1791)"
local e_season = mw.ustring.match(cpagename, '%s(%d+[–-])$') or --irreg; ending unknown, e.g. "Members of the Scottish Parliament 2021–"
mw.ustring.match(cpagename, '%s(%d+[–-]present)$') --e.g. "UK MPs 2019–present"
local season = mw.ustring.match(cpagename, '[:%s%(](%d+[–-]%d+)[%)%s]') or --split in 2 b/c you can't frontier '$'/eos?
mw.ustring.match(cpagename, '[:%s](%d+[–-]%d+)$')
local tvseason = mw.ustring.match(cpagename, 'الموسم (%d+)') or
mw.ustring.match(cpagename, 'series (%d+)')
local nordinal = mw.ustring.match(cpagename, '[:%s](%d+[snrt][tdh])[-%s]') or
mw.ustring.match(cpagename, '[:%s](%d+[snrt][tdh])$')
local decade = mw.ustring.match(cpagename, '[%:%s]عقد%s(%d+)[%s-]') or
mw.ustring.match(cpagename, '[%:%s]عقد%s(%d+)%s') or
mw.ustring.match(cpagename, '[%:%s]عقد%s(%d+)%sق%sم%s') or
mw.ustring.match(cpagename, '[%:%s]عقد%s(%d+)$')
local century = mw.ustring.match(cpagename, '[:%s]القرن%s(%d+)[%s-]') or
mw.ustring.match(cpagename, '[:%s]القرن%s(%d+)%s') or
mw.ustring.match(cpagename, '[:%s]القرن%s(%d+)%s') or
mw.ustring.match(cpagename, '[:%s]القرن%s(%d+)%sق%sم') or
mw.ustring.match(cpagename, '[:%s]القرن%s(%d+)$')
local millennium = mw.ustring.match(cpagename, '[:%s]الألفية%s(%d+)[%s-]') or
mw.ustring.match(cpagename, '[:%s]الألفية%s(%d+)%s') or
mw.ustring.match(cpagename, '[:%s]الألفية%s(%d+)$')
local year = mw.ustring.match(cpagename, '[:%s](%d+)$') or --%) for [[Category:Futurama (season 1) episodes]], etc.
mw.ustring.match(cpagename, '[:%s](%d+)[%s%)]') or
mw.ustring.match(cpagename, '[:ب](%d+)$')
local year44 = mw.ustring.match(cpagename, '[:%s](%d%d%d%d)%s') or --prioritize 4-digit years
mw.ustring.match(cpagename, '[:%s](%d%d%d%d)$') or
mw.ustring.match(cpagename, '[:%s](%d+)%s') or
mw.ustring.match(cpagename, '[:%s](%d+)$') or
--expand/combine exceptions below as needed
mw.ustring.match(cpagename, '[:%s](%d+)-related') or
mw.ustring.match(cpagename, '[:%s](%d+)-cylinder') or
mw.ustring.match(cpagename, '[:%-VW](%d+)%s') --e.g. "Straight-8 engines"
local roman = mw.ustring.match(cpagename, '%s([IVXLCDM]+)%s')
local found = d_season or y_season or e_season or season or tvseason or
nordinal or decade or year or roman
if found then
if string.match(found, '%d%d%d%d%d') == nil then
--return in order of decreasing complexity/least chance for duplication
if nordinal and season --i.e. "18th-century establishments in the Province of Quebec (1763–1791)"
then return { ['vtype'] = 'nordinal', ['v'] = nordinal } end
if millennium then return { ['vtype'] = 'nordinal', ['v'] = millennium } end
if century then return { ['vtype'] = 'century', ['v'] = century } end
if d_season then return { ['vtype'] = 'decade', ['v'] = d_season } end
if y_season then return { ['vtype'] = 'year', ['v'] = y_season } end
if e_season then return { ['vtype'] = 'ending', ['v'] = e_season } end
if season then return { ['vtype'] = 'season', ['v'] = season } end
if tvseason then return { ['vtype'] = 'tvseason', ['v'] = tvseason } end
if nordinal then return { ['vtype'] = 'nordinal', ['v'] = nordinal } end
if decade then return { ['vtype'] = 'decade', ['v'] = decade } end
if year then return { ['vtype'] = 'year', ['v'] = year } end
if roman then return { ['vtype'] = 'roman', ['v'] = roman } end
end
else
--try wordinals ('zeroth' to 'ninety-ninth' only)
local eng2ord = require('Module:ConvertNumeric/en').english_to_ordinal
local split = mw.text.split(pagename, ' ')
for i=1, #split do
if eng2ord(split[i]) > -1 then
return { ['vtype'] = 'wordinal', ['v'] = split[i] }
end
end
--[[
--try English numerics ('one'/'single' to 'ninety-nine' only)
local eng2num = require('Module:ConvertNumeric/en').english_to_numeral
local split = mw.text.split(pagename, '[%s%-]') --e.g. "Nine-cylinder engines"
for i=1, #split do
if eng2num(split[i]) > -1 then
return { ['vtype'] = 'enumeric', ['v'] = split[i] }
end
end]]
end
errors = p.errorclass('Function find_var can\'t find the variable text in category "'..pagename..'".')
return { ['vtype'] = 'error', ['v'] = p.failedcat(errors, 'V') }
end
--[[==========================================================================]]
--[[ Main ]]
--[[==========================================================================]]
function p.navseasoncats( frame )
--arg checks & handling
local args = frame:getParent().args
checkforunknownparams(args) --for template args
checkforunknownparams(frame.args) --for #invoke'd args
local cat = args['cat'] --'testcase' alias for catspace
local list = args['list-all-links'] --debugging utility to output all links & followed #Rs
local follow = args['follow-redirects'] --default 'yes'
local testcase = args['testcase']
local testcasegap = args['testcasegap']
local minimum = args['min']
local maximum = args['max']
local skip_gaps = args['skip-gaps']
--apply args
local pagename = testcase or cat or currtitle.text
local testcaseindent = ''
if testcasecolon == ':' then testcaseindent = '\n::' end
if follow and follow == 'no' then followRs = false end
if list and list == 'yes' then listall = true end
if skip_gaps and skip_gaps == 'yes' then
skipgaps = true
trackcat(26, 'Navseasoncats using skip-gaps parameter')
end
--ns checks
if currtitle.nsText == 'تصنيف' then
if cat and cat ~= '' then
trackcat(1, 'Navseasoncats using cat parameter')
end
if testcase and testcase ~= '' then
trackcat(2, 'Navseasoncats using testcase parameter')
end
elseif currtitle.nsText == '' then
trackcat(30, 'Navseasoncats in mainspace')
end
--find the variable parts of pagename
local findvar = find_var(pagename)
if findvar.vtype == 'error' then --basic format error checking in find_var()
return findvar.v..table.concat(ttrackingcats)
end
local start = string.match(findvar.v, '^%d+')
mw.log('findvar.vtype:' .. findvar.vtype)
--the rest is static
local findvar_escaped = string.gsub( findvar.v, '%-', '%%%-')
local firstpart, lastpart = string.match(pagename, '^(.-)'..findvar_escaped..'(.*)$')
if findvar.vtype == 'tvseason' then --double check for cases like "30 Rock (season 3) episodes"
firstpart, lastpart = string.match(pagename, '^(.-season )'..findvar_escaped..'(.*)$')
if firstpart == nil then
firstpart, lastpart = string.match(pagename, '^(.-series )'..findvar_escaped..'(.*)$')
end
end
firstpart = mw.text.trim(firstpart or '')
lastpart = mw.text.trim(lastpart or '')
--call the appropriate nav function, in order of decreasing popularity
if findvar.vtype == 'year' then --e.g. "500", "2001"; nav_year..nav_decade; ~75% of cats
local nav1 = nav_year( frame, firstpart, start, lastpart, minimum, maximum )..testcaseindent..table.concat(ttrackingcats)
local dec = math.floor(findvar.v/10)
local decadecat = nil
local firstpart_dec = firstpart
if firstpart_dec ~= '' then
firstpart_dec = firstpart_dec..' '
elseif firstpart_dec == 'AD' and dec <= 1 then
firstpart_dec = ''
if dec == 0 then dec = '' end
end
-- local decade = dec .. '0s '
local decade = dec .. '0 '
if mw.text.trim(decade) == '00' then decade = '0 ' end
firstpart_dec = firstpart_dec .. ' عقد '
firstpart_dec = string.gsub(firstpart_dec, ' سنة%s*عقد%s*$', ' عقد ')
decadecat = mw.text.trim( firstpart_dec..' '..decade..lastpart )
local exists = catexists(decadecat)
mw.log('find cat:' .. decadecat )
if exists then
navborder = false
trackcat(28, 'Navseasoncats year and decade')
local nav2 = nav_decade( frame, firstpart_dec, decade, lastpart, minimum, maximum )..testcaseindent..table.concat(ttrackingcats)
return nav1nav2( nav1, nav2 )
elseif ttrackingcats[16] ~= '' then --nav_year isolated; check nav_hyphen (e.g. UK MPs 1974, Moldovan MPs 2009, etc.)
local hyphen = '–'
local finish = start
local nav2 = nav_hyphen( frame, start, hyphen, finish, firstpart, lastpart, minimum, maximum, testcasegap )..testcaseindent..table.concat(ttrackingcats)
if ttrackingcats[16] ~= '' then return nav1 --still isolated; rv to nav_year
else return nav2 end
else --regular nav_year
return nav1
end
elseif findvar.vtype == 'decade' then --e.g. "0s", "2010s"; nav_decade..nav_nordinal; ~12% of cats
local nav1 = nav_decade( frame, firstpart, start, lastpart, minimum, maximum )..testcaseindent..table.concat(ttrackingcats)
-- local decade = tonumber(string.match(findvar.v, '^(%d+)s'))
local decade = tonumber(string.match(findvar.v, '^(%d+)'))
local century = math.floor( ((decade-1)/100) + 1 ) --from {{CENTURY}}
if century == 0 then century = 1 end --no 0th century
if string.match(decade, '00$') then
century = century + 1 --'2000' is in the 20th, but the rest of the 2000s is in the 21st
end
local clastpart = ' ' .. lastpart
if firstpart == "عقد" then
firstpart = " القرن "
else
firstpart = string.gsub(firstpart, ' عقد%s*$', ' القرن ')
end
local centurycat = mw.text.trim( firstpart .. century .. clastpart )
--mw.log('centurycat:' .. centurycat)
local exists = catexists(centurycat)
if not exists then --check for hyphenated century
clastpart = ' ' .. lastpart
centurycat = mw.text.trim( firstpart .. century .. clastpart )
exists = catexists(centurycat)
end
if exists then
navborder = false
trackcat(29, 'Navseasoncats decade and century')
local nav2 = nav_nordinal( frame, firstpart, century, clastpart, minimum, maximum )..testcaseindent..table.concat(ttrackingcats)
return nav1nav2( nav1, nav2 )
else
return nav1
end
elseif findvar.vtype == 'nordinal' or findvar.vtype == 'century' then --e.g. "1st", "99th"; ~7.5% of cats
return nav_nordinal( frame, firstpart, start, lastpart, minimum, maximum )..testcaseindent..table.concat(ttrackingcats)
elseif findvar.vtype == 'season' then --e.g. "1–4", "1999–2000", "2001–02", "2001–2002", "2005–2010", etc.; ~5.25%
local hyphen, finish = mw.ustring.match(findvar.v, '%d([–-])(%d+)') --ascii 150 & 45 (ndash & keyboard hyphen); mw req'd
return nav_hyphen( frame, start, hyphen, finish, firstpart, lastpart, minimum, maximum, testcasegap )..testcaseindent..table.concat(ttrackingcats)
elseif findvar.vtype == 'tvseason' then --e.g. "1", "15" but preceded with "season" or "series"; <1% of cats
return nav_tvseason( frame, firstpart, start, lastpart, maximum )..testcaseindent..table.concat(ttrackingcats) --"minimum" defaults to 1
elseif findvar.vtype == 'wordinal' then --e.g. "first", "ninety-ninth"; <<1% of cats
local ordinal = true
return nav_wordinal( frame, firstpart, findvar.v, lastpart, minimum, maximum, ordinal, frame )..testcaseindent..table.concat(ttrackingcats)
elseif findvar.vtype == 'enumeric' then --e.g. "one", "ninety-nine"; <<1% of cats
local ordinal = false
return nav_wordinal( frame, firstpart, findvar.v, lastpart, minimum, maximum, ordinal, frame )..testcaseindent..table.concat(ttrackingcats)
elseif findvar.vtype == 'roman' then --e.g. "I", "XXVIII"; <<1% of cats
return nav_roman( frame, firstpart, findvar.v, lastpart, minimum, maximum )..testcaseindent..table.concat(ttrackingcats)
elseif findvar.vtype == 'ending' then --e.g. "2021–" (irregular; ending unknown); <<<1% of cats
local hyphen, finish = mw.ustring.match(findvar.v, '%d([–-])present$'), -1 --ascii 150 & 45 (ndash & keyboard hyphen); mw req'd
if hyphen == nil then
hyphen, finish = mw.ustring.match(findvar.v, '%d([–-])$'), 0 --0/-1 are hardcoded switches for nav_hyphen()
end
return nav_hyphen( frame, start, hyphen, finish, firstpart, lastpart, minimum, maximum, testcasegap )..testcaseindent..table.concat(ttrackingcats)
else --malformed
errors = p.errorclass('Failed to determine the appropriate nav function from malformed season "'..findvar.v..'". ')
return p.failedcat(errors, 'N')..table.concat(ttrackingcats)
end
end
return p