Jump to content

Module:ⴰⵙⵎⵍⵓⵙⵙⴰⵏ

ⵙⴳ ⵡⵉⴽⵉⴱⵉⴷⵢⴰ
local p = {}

local monthsData = {
    ['ⵉⵏⵏⴰⵢⵔ']        = {en='January',   days=31, order=1,  prev='ⴷⵓⵊⴰⵏⴱⵉⵔ', next='ⴱⵕⴰⵢⵕ'},
    ['ⴱⵕⴰⵢⵕ']        = {en='February',  days=29, order=2,  prev='ⵉⵏⵏⴰⵢⵔ', next='ⵎⴰⵕⵚ'},
    ['ⵎⴰⵕⵚ']          = {en='March',     days=31, order=3,  prev='ⴱⵕⴰⵢⵕ', next='ⵉⴱⵔⵉⵔ'},
    ['ⵉⴱⵔⵉⵔ']        = {en='April',     days=30, order=4,  prev='ⵎⴰⵕⵚ', next='ⵎⴰⵢⵢⵓ'},
    ['ⵎⴰⵢⵢⵓ']        = {en='May',        days=31, order=5,  prev='ⵉⴱⵔⵉⵔ', next='ⵢⵓⵏⵢⵓ'},
    ['ⵢⵓⵏⵢⵓ']        = {en='June',       days=30, order=6,  prev='ⵎⴰⵢⵢⵓ', next='ⵢⵓⵍⵢⵓⵣ'},
    ['ⵢⵓⵍⵢⵓⵣ']       = {en='July',       days=31, order=7,  prev='ⵢⵓⵏⵢⵓ', next='ⵖⵓⵛⵜ'},
    ['ⵖⵓⵛⵜ']          = {en='August',    days=31, order=8,  prev='ⵢⵓⵍⵢⵓⵣ', next='ⵛⵓⵜⴰⵏⴱⵉⵔ'},
    ['ⵛⵓⵜⴰⵏⴱⵉⵔ']    = {en='September', days=30, order=9,  prev='ⵖⵓⵛⵜ', next='ⴽⵟⵓⴱⵕ'},
    ['ⴽⵟⵓⴱⵕ']        = {en='October',   days=31, order=10, prev='ⵛⵓⵜⴰⵏⴱⵉⵔ', next='ⵏⵓⵡⴰⵏⴱⵉⵔ'},
    ['ⵏⵓⵡⴰⵏⴱⵉⵔ']    = {en='November',  days=30, order=11, prev='ⴽⵟⵓⴱⵕ', next='ⴷⵓⵊⴰⵏⴱⵉⵔ'},
    ['ⴷⵓⵊⴰⵏⴱⵉⵔ']    = {en='December',  days=31, order=12, prev='ⵏⵓⵡⴰⵏⴱⵉⵔ', next='ⵉⵏⵏⴰⵢⵔ'}
}

local monthList = {
    'ⵉⵏⵏⴰⵢⵔ', 'ⴱⵕⴰⵢⵕ', 'ⵎⴰⵕⵚ', 'ⵉⴱⵔⵉⵔ', 'ⵎⴰⵢⵢⵓ', 'ⵢⵓⵏⵢⵓ', 
    'ⵢⵓⵍⵢⵓⵣ', 'ⵖⵓⵛⵜ', 'ⵛⵓⵜⴰⵏⴱⵉⵔ', 'ⴽⵟⵓⴱⵕ', 'ⵏⵓⵡⴰⵏⴱⵉⵔ', 'ⴷⵓⵊⴰⵏⴱⵉⵔ'
}

local COLORS = {
    border = '#CDDC39',
    header = '#CDDC39',
    bgMain = '#FCFFDA',
    bgCell = '#FFFFEE',
    bgSelected = '#E6EE9C',
    text = 'black'
}

local function trimWhitespace(s)
    if type(s) ~= 'string' then return nil end
    s = s:match('^%s*(.-)%s*$')
    if s == '' then return nil end
    return s
end

local function addEditIcon(entityId, propertyId)
    if not entityId or not propertyId then return '' end
    return ' [[File:Edit-icon.svg|12px|link=https://www.wikidata.org/wiki/' .. entityId .. '#' .. propertyId .. '|title=ⵙⵏⴼⵍ ⴳ ⵡⵉⴽⵉⴷⴰⵜⴰ]]'
end

local function tifinaghToLatin(str)
    if not str then return nil end
    local map = {
        ['ⵇ']='q', ['ⵡ']='w', ['ⴻ']='e', ['ⵔ']='r', ['ⵜ']='t', ['ⵢ']='y', ['ⵓ']='u', ['ⵉ']='i', ['ⴰ']='a',
        ['ⵙ']='s', ['ⴷ']='d', ['ⴼ']='f', ['ⴳ']='g', ['ⵀ']='h', ['ⵊ']='j', ['ⴽ']='k', ['ⵍ']='l', ['ⵣ']='z',
        ['ⵅ']='x', ['ⵛ']='c', ['ⴱ']='b', ['ⵏ']='n', ['ⵎ']='m', ['ⵄ']='ɛ', ['ⵟ']='ṭ', ['ⵃ']='ḥ', ['ⵖ']='ɣ',
        ['ⴹ']='ḍ', ['ⵚ']='ṣ', ['ⵕ']='ṛ', ['ⵥ']='ẓ', ['ⵯ']='ʷ'
    }
    return mw.ustring.gsub(str, '.', map)
end

local function getAmazighDate(day, monthKey)
    local currentMonthIndex = monthsData[monthKey].order
    local daysAccumulated = day
    for i = 1, currentMonthIndex - 1 do
        daysAccumulated = daysAccumulated + monthsData[monthList[i]].days
    end
    
    local amazighTotalDays = daysAccumulated - 13
    if amazighTotalDays <= 0 then
        amazighTotalDays = amazighTotalDays + 365
    end
    
    local amzMonthIndex = 1
    while amazighTotalDays > monthsData[monthList[amzMonthIndex]].days do
        amazighTotalDays = amazighTotalDays - monthsData[monthList[amzMonthIndex]].days
        amzMonthIndex = amzMonthIndex + 1
        if amzMonthIndex > 12 then amzMonthIndex = 1 end
    end
    
    return amazighTotalDays, monthList[amzMonthIndex]
end

local function getWikidataLabels(entityId)
    if not entityId then return nil end
    local entity = mw.wikibase.getEntity(entityId)
    if not entity or not entity.labels then return nil end
    
    local container = mw.html.create('div')
    container:addClass('mw-collapsible mw-collapsed')
    
    local toggleText = container:tag('div')
    toggleText:css('font-weight', 'bold')
    toggleText:css('font-size', '90%')
    toggleText:wikitext('ⴼⵙⵉ ⵜⴰⵍⴳⴰⵎⵜ')
    
    local content = container:tag('div')
    content:addClass('mw-collapsible-content')
    content:css('font-size', '90%')
    content:css('padding-top', '5px')

    local hasContent = false

    if entity.labels['zgh'] then
        local zghVal = entity.labels['zgh'].value
        local shiVal = tifinaghToLatin(zghVal)
        content:tag('div'):wikitext("'''" .. shiVal .. "''' ([[ⵜⴰⵛⵍⵃⵉⵜ]])")
        hasContent = true
    end

    local targetLangs = {
        {code='fr', name='ⵜⴰⴼⵕⴰⵏⵚⵉⵚⵜ'},
        {code='es', name='ⵜⴰⵚⴱⵍⵢⵓⵏⵜ'},
        {code='de', name='ⵜⴰⵍⵉⵎⴰⵏⵜ'},
        {code='he', name='ⵜⴰⵄⵉⴱⵔⵉⵜ'}
    }
    
    for _, lang in ipairs(targetLangs) do
        if entity.labels[lang.code] then
            content:tag('div'):wikitext("'''" .. entity.labels[lang.code].value .. "''' ([[" .. lang.name .. "]])")
            hasContent = true
        end
    end
    
    if not hasContent then return nil end
    return tostring(container)
end

local function getRecentYearsList(day, monthOrder)
    local weekDaysAmz = {
        [0] = 'ⴰⵙⴰⵎⴰⵙ',
        [1] = 'ⴰⵢⵏⴰⵙ',
        [2] = 'ⴰⵙⵉⵏⴰⵙ',
        [3] = 'ⴰⴽⵕⴰⵙ',
        [4] = 'ⴰⴽⵡⴰⵙ',
        [5] = 'ⴰⵙⵉⵎⵡⴰⵙ',
        [6] = 'ⴰⵙⵉⴹⵢⴰⵙ'
    }
    
    local currentYear = tonumber(os.date("%Y"))
    local listContainer = mw.html.create('div')
    listContainer:addClass('mw-collapsible mw-collapsed')
    
    local successCurrent, timeCurrent = pcall(os.time, {year=currentYear, month=monthOrder, day=day})
    local headerText
    if successCurrent then
        local wDay = tonumber(os.date("%w", timeCurrent))
        headerText = currentYear .. ' (' .. weekDaysAmz[wDay] .. ')'
    else
        headerText = day .. ' ' .. monthList[monthOrder]
    end
    
    local header = listContainer:tag('div')
    header:css('font-weight', 'bold')
    header:wikitext(headerText)
    
    local content = listContainer:tag('div')
    content:addClass('mw-collapsible-content')
    
    local ul = content:tag('ul')
    ul:css('margin', '0'):css('padding-left', '1.5em')

    for y = currentYear - 1, currentYear - 10, -1 do
        local success, time = pcall(os.time, {year=y, month=monthOrder, day=day})
        if success then
            local wDay = tonumber(os.date("%w", time))
            local dayName = weekDaysAmz[wDay]
            ul:tag('li')
                :wikitext("'''" .. y .. "''' (" .. dayName .. ")")
                :css('font-size', '90%')
        end
    end
    
    return tostring(listContainer)
end

function p.main(frame)
    local args = frame:getParent().args
    local title = mw.title.getCurrentTitle().text
    
    local dayArg = args[1] or title:match("^(%d+)")
    local monthArg = args[2] or title:match("%d+%s+(.+)$")
    
    if not dayArg or not monthArg then
        return ""
    end
    
    local day = tonumber(dayArg)
    local monthName = trimWhitespace(monthArg)
    local monthInfo = monthsData[monthName]
    
    if not monthInfo then return "" end
    
    local entityId = mw.wikibase.getEntityIdForCurrentPage()

    local root = mw.html.create('table')
    root:addClass('infobox')
    root:css({
        ['width'] = '26em',
        ['border'] = '1px solid ' .. COLORS.border,
        ['border-spacing'] = '4px',
        ['background-color'] = COLORS.bgMain,
        ['color'] = COLORS.text,
        ['font-size'] = '90%',
        ['float'] = 'right',
        ['clear'] = 'right',
        ['margin'] = '0.5em 0 0.5em 1em'
    })
    
    local headerRow = root:tag('tr')
    local headerCell = headerRow:tag('th')
        :attr('colspan', 2)
        :css({
            ['background-color'] = COLORS.header,
            ['color'] = 'black',
            ['padding'] = '0.4em',
            ['text-align'] = 'center',
            ['font-weight'] = 'bold',
            ['font-size'] = '125%',
            ['position'] = 'relative'
        })

    local headerContainer = mw.html.create('div')
        :css({
            ['padding-right'] = '50px',
            ['padding-left'] = '50px',
        })
        :wikitext(day .. " " .. monthName)
    headerCell:node(headerContainer)

    local iconContainer = mw.html.create('div')
        :css({
            ['position'] = 'absolute',
            ['top'] = '1px',
            ['right'] = '1px',
        })
        :wikitext('[[ⴰⴼⴰⵢⵍⵓ:Almanacco.png|45px|alt=ⵜⴰⵢⴽⵓⵏⵜ|link=]]')
    
    headerCell:node(iconContainer)

    local englishDate = (monthInfo.en or '') .. " " .. day
    local subHeaderRow = root:tag('tr')
    local subHeaderCell = subHeaderRow:tag('td')
        :attr('colspan', 2)
        :css('text-align', 'center')
        :css('background-color', COLORS.bgCell)
        
    subHeaderCell:tag('div')
        :css('font-weight', 'bold')
        :wikitext("'''" .. englishDate .. "''' <small>([[ⵜⴰⵏⴳⵍⵉⵣⵜ]])</small>")
        
    local imageArg = args['ⵜⴰⵡⵍⴰⴼⵜ'] or args['image']
    local imageCode
    
    if imageArg and imageArg ~= '' then
        if not (string.match(imageArg, '^File:') or string.match(imageArg, '^ⴰⴼⴰⵢⵍⵓ:')) then
            imageArg = 'ⴰⴼⴰⵢⵍⵓ:' .. imageArg
        end
        imageCode = "[[" .. imageArg .. "|frameless|250px|center]]"
    else
        local defaultImageName = string.format("ⴰⴼⴰⵢⵍⵓ:%d-%s.ZGH.png", day, monthName)
        imageCode = "[[" .. defaultImageName .. "|frameless|250px|center]]"
    end

    root:tag('tr')
        :tag('td')
            :attr('colspan', 2)
            :css('text-align', 'center')
            :css('padding', '5px 0')
            :css('background-color', 'transparent')
            :wikitext(imageCode)

    root:tag('tr'):tag('th')
        :attr('colspan', 2)
        :css('background-color', COLORS.header)
        :css('color', 'black')
        :css('text-align', 'center')
        :wikitext('ⵉⵙⴼⴽⴰ')

    local function addRow(label, value)
        if not value then return end
        local row = root:tag('tr')
        row:tag('th')
            :css('text-align', 'left')
            :css('background-color', COLORS.bgMain)
            :css('width', '50%')
            :css('padding-left', '5px')
            :css('font-weight', 'normal')
            :wikitext(label)
        row:tag('td')
            :css('padding-left', '5px')
            :css('background-color', COLORS.bgCell)
            :wikitext(value)
    end

    addRow('ⴰⵢⵢⵓⵔ', '[[' .. monthName .. ']]')
    
    local pageType = day and 'ⴰⵙⵙ ⴳ ⵓⵙⴳⴳⵯⴰⵙ' or 'ⴰⵢⵢⵓⵔ ⴳ ⵓⵙⴳⴳⵯⴰⵙ'
    addRow('ⴰⵙⵎⵉⵍ', pageType)

    local currentYearVal = os.date("%Y")
    addRow('ⴰⵙⴳⴳⵯⴰⵙ ⴰ', '[[' .. currentYearVal .. ']]') 

    addRow('ⵜⵉⵏⵉⴼⴹⵜ', '[[2000]] (<small>ⵜⵉⵙⵙ ⴽⵕⴰⴹⵜ</small>)')

    local translations = getWikidataLabels(entityId)
    addRow('ⵙ ⵜⵓⵜⵍⴰⵢⵉⵏ ⵏⵏⵉⴹⵏ', translations)

    local amzDay, amzMonth = getAmazighDate(day, monthName)
    addRow('ⴳ ⵓⵙⵎⵍⵓⵙⵙⴰⵏ ⴰⵎⴰⵣⵉⵖ', "'''[[" .. amzDay .. " " .. amzMonth .. "]]'''")
    
    addRow('ⴰⵙⵙ ⴳ ⵉⵙⴳⴳⵓⵙⴰ ⵉⵣⵔⵉⵏ', getRecentYearsList(day, monthInfo.order))

    local calRow = root:tag('tr'):tag('td'):attr('colspan', 2)
    local calTable = mw.html.create('table')
    calTable:css('width', '100%')
            :css('text-align', 'center')
            :css('border-collapse', 'collapse')
            :css('table-layout', 'fixed')
            :css('border', '1px solid ' .. COLORS.header)

    local monthNavRow = calTable:tag('tr')
    local monthNavCell = monthNavRow:tag('th')
        :attr('colspan', 7)
        :css('background-color', COLORS.header)
        :css('border-bottom', '1px solid white')
        :css('padding', '3px 5px')
        
    local monthNavContainer = mw.html.create('div')
        :css('display', 'flex')
        :css('justify-content', 'space-between')
        :css('align-items', 'center')
        :css('font-weight', 'bold')

    monthNavContainer:tag('span')
        :wikitext('[[' .. monthInfo.prev .. '|◀]]')
        :css('cursor', 'pointer')

    monthNavContainer:tag('span')
        :wikitext('[[' .. monthName .. ']]')
        :css('font-size', '110%')

    monthNavContainer:tag('span')
        :wikitext('[[' .. monthInfo.next .. '|▶]]')
        :css('cursor', 'pointer')

    monthNavCell:node(monthNavContainer)

    local weekRow = calTable:tag('tr')
    local weekDays = {
        '[[ⴰⵢⵏⴰⵙ|ⴰⵢⵏ]]', 
        '[[ⴰⵙⵉⵏⴰⵙ|ⴰⵙⵉⵏ]]', 
        '[[ⴰⴽⵕⴰⵙ|ⴰⴽⵕ]]', 
        '[[ⴰⴽⵡⴰⵙ|ⴰⴽⵡ]]', 
        '[[ⴰⵙⵉⵎⵡⴰⵙ|ⴰⵙⵉⵎ]]', 
        '[[ⴰⵙⵉⴹⵢⴰⵙ|ⴰⵙⵉⴹ]]', 
        '[[ⴰⵙⴰⵎⴰⵙ|ⴰⵙⴰ]]'
    }
    
    for _, d in ipairs(weekDays) do
        weekRow:tag('th')
            :css('border-bottom', '1px solid ' .. COLORS.border)
            :css('font-size', '85%')
            :css('white-space', 'nowrap')
            :css('background-color', COLORS.header)
            :wikitext(d)
    end

    local currentYear = tonumber(os.date("%Y"))
    local firstDayTime = os.time({year=currentYear, month=monthInfo.order, day=1})
    local firstDayWday = tonumber(os.date("%w", firstDayTime))
    local skipCells = (firstDayWday + 6) % 7 

    local totalDays = monthInfo.days
    local currentGridDay = 1
    local row = calTable:tag('tr')
    local cellCount = 0

    local prevMonthNameKey = monthInfo.prev
    local prevMonthTotalDays = monthsData[prevMonthNameKey].days
    local fillDayStart = prevMonthTotalDays - skipCells + 1

    for i = 1, skipCells do
        local cell = row:tag('td')
        cell:css('border', '1px solid ' .. COLORS.border)
        cell:css('background-color', '#f9f9f9')
        cell:css('color', '#aaa')
        cell:css('padding', '2px')
        cell:css('height', '2.5em')
        cell:wikitext(fillDayStart)
        fillDayStart = fillDayStart + 1
        cellCount = cellCount + 1
    end

    while currentGridDay <= totalDays do
        cellCount = cellCount + 1
        
        local cellAmzDay, cellAmzMonth = getAmazighDate(currentGridDay, monthName)
        local cell = row:tag('td')
        cell:css('border', '1px solid ' .. COLORS.border)
        cell:css('padding', '2px')
        cell:css('vertical-align', 'top')
        cell:css('height', '2.5em')
        
        if currentGridDay == day then
            cell:css('background-color', COLORS.bgSelected)
            cell:css('border', '2px solid ' .. COLORS.border)
        else
            cell:css('background-color', COLORS.bgCell)
        end

        local dayLink = string.format("[[ %d %s|%d]]", currentGridDay, monthName, currentGridDay)
        if currentGridDay == day then
            dayLink = "'''" .. currentGridDay .. "'''"
        end
        
        cell:wikitext(dayLink)
        
        local amzDateDiv = cell:tag('div')
        amzDateDiv:css('font-size', '75%')
                  :css('line-height', '1')
                  :css('margin-top', '3px')
        
        local span = amzDateDiv:tag('span')
        span:attr('title', 'ⴰⵙⵙ ⴰⵎⴰⵣⵉⵖ')
        span:attr('tabindex', '0')
        span:css('color', '#666')
        span:css('border-bottom', '1px dotted #888')
        span:css('cursor', 'help')
        span:wikitext(cellAmzDay)
        
        if cellCount % 7 == 0 and currentGridDay < totalDays then
            row = calTable:tag('tr')
        end
        currentGridDay = currentGridDay + 1
    end

    local nextMonthDayCounter = 1
    while cellCount % 7 ~= 0 do
        local cell = row:tag('td')
        cell:css('border', '1px solid ' .. COLORS.border)
        cell:css('background-color', '#f9f9f9')
        cell:css('color', '#aaa')
        cell:css('padding', '2px')
        cell:css('height', '2.5em')
        cell:wikitext(nextMonthDayCounter)
        nextMonthDayCounter = nextMonthDayCounter + 1
        cellCount = cellCount + 1
    end

    calRow:node(calTable)

    local prevDayNum = day - 1
    local prevMonthName = monthName
    local nextDayNum = day + 1
    local nextMonthName = monthName

    if prevDayNum < 1 then
        prevMonthName = monthInfo.prev
        prevDayNum = monthsData[prevMonthName].days
    end

    if nextDayNum > monthInfo.days then
        nextMonthName = monthInfo.next
        nextDayNum = 1
    end

    local navRow = root:tag('tr'):tag('td')
        :attr('colspan', 2)
        :css('background-color', COLORS.header)
        :css('padding', '4px 8px')
    
    local navDiv = mw.html.create('div')
        :css('display', 'flex')
        :css('justify-content', 'space-between')
        :css('align-items', 'center')
        :css('font-weight', 'bold')
        :css('font-size', '90%')
        :css('width', '100%')

    navDiv:tag('div')
        :wikitext(string.format("[[%d %s|◀ %d %s]]", prevDayNum, prevMonthName, prevDayNum, prevMonthName))
    
    navDiv:tag('div')
        :wikitext(string.format("[[%d %s|%d %s ▶]]", nextDayNum, nextMonthName, nextDayNum, nextMonthName))
        
    navRow:node(navDiv)

    local currentTitle = mw.title.getCurrentTitle()
    local editSourceUrl = currentTitle:fullUrl({action='edit', section='0'})
    local editVisualUrl = currentTitle:fullUrl({veaction='edit'})
    local templateDocUrl = mw.title.new('ⴰⵍⴱⵓⴹ:ⴰⵙⵎⵍⵓⵙⵙⴰⵏ'):fullUrl()

    local footerRow = root:tag('tr')
    local footerCell = footerRow:tag('td')
        :attr('colspan', 2)
        :css({
            ['padding'] = '0.2em',
            ['font-size'] = '85%',
            ['text-align'] = 'left',
            ['background-color'] = '#f8f8f8',
            ['border-top'] = '1px solid ' .. COLORS.border
        })

    local footerContainer = mw.html.create('div')
        :css({
            ['display'] = 'flex',
            ['justify-content'] = 'space-between',
            ['align-items'] = 'center',
        })

    local editLinksSpan = footerContainer:tag('span'):addClass('plainlinks')
    if entityId and entityId ~= '' then
        local wikidataUrl = 'https://www.wikidata.org/wiki/Special:EntityPage/' .. entityId
        editLinksSpan:wikitext('[' .. editSourceUrl .. ' <span style="color:#002bb8;">ⵙⵏⴼⵍ ⴰⵙⴰⴳⵎ</span>] - [' ..
            editVisualUrl .. ' <span style="color:#002bb8;">ⵙⵏⴼⵍ</span>] - [' ..
            wikidataUrl .. ' <span style="color:#002bb8;">ⵡⵉⴽⵉⴷⴰⵜⴰ</span>]')
    else
        editLinksSpan:wikitext('[' .. editSourceUrl .. ' <span style="color:#002bb8;">ⵙⵏⴼⵍ ⴰⵙⴰⴳⵎ</span>] - [' ..
            editVisualUrl .. ' <span style="color:#002bb8;">ⵙⵏⴼⵍ</span>]')
    end

    footerContainer:tag('span')
        :css({['float'] = 'right', ['margin-left'] = '5px'})
        :wikitext('[[ⴰⴼⴰⵢⵍⵓ:Info Simple.svg|15px|ⵥⵕ ⵓⴳⴳⴰⵔ ⵅⴼ ⵡⴰⵍⴱⵓⴹ ⴰⴷ |link=' .. templateDocUrl .. ']]')

    footerCell:node(footerContainer)

    return tostring(root)
end

return p