Wikizvor
bswikisource
https://bs.wikisource.org/wiki/Po%C4%8Detna_strana
MediaWiki 1.47.0-wmf.14
first-letter
Mediji
Posebno
Razgovor
Korisnik
Razgovor s korisnikom
Wikizvor
Razgovor o o Wikizvor
Datoteka
Razgovor o datoteci
MediaWiki
Razgovor o MediaWikiju
Šablon
Razgovor o šablonu
Pomoć
Razgovor o pomoći
Kategorija
Razgovor o kategoriji
Page
Page talk
Index
Index talk
TimedText
TimedText talk
Modul
Razgovor o modulu
Event
Event talk
Modul:Header
828
5524
12147
12115
2026-08-11T11:48:53Z
Vratiosevalter
3520
12147
Scribunto
text/plain
require('strict')
local p = {}
local getArgsRaw = require('Modul:Arguments').getArgs
local yesno = require('Modul:Yesno')
local headerAttribution = require('Modul:Header/attribution')
local headerLang = require('Modul:Header/lang')
local constructDefaultsort = require('Modul:Header/sort').construct_defaultsort
local constructYear = require('Modul:Header/year').construct_year
local constructHeader = require('Modul:Header structure').construct_header
local plainSister = require('Modul:Plain sister')._plain_sister
local parentLinks = require('Modul:Auto_parents')._parent_links
local TRANSLATION_NS_ID = 114 -- placeholder, vidi otvoreno pitanje 2
------------------------------------------------------------------------
-- Bosanski aliasi parametara (Faza 1 odluka #4). NAPOMENA: namjerno NE
-- koristimo Modul:Arguments options.translate mehanizam — taj
-- mehanizam je jednosmjerno preusmjeravanje ključa (moje_ime → sirovi
-- ključ), pa ne može istovremeno podržati i "author=" i "autor=" kao
-- validne ulaze. Umjesto toga, ručno spajamo frame.args + parent.args
-- PRIJE poziva getArgs, razrješavajući bosanske alias ključeve u
-- engleske. Ako korisnik da OBA (npr. i autor= i author=), engleski
-- ima prednost — sprječava tihi konflikt (zahtjev zadatka, tačka 5.4).
------------------------------------------------------------------------
local ALIAS_BASE = {
autor = 'author', prevodilac = 'translator', urednik = 'editor',
kompozitor = 'composer', ilustrator = 'illustrator', saradnik = 'contributor',
naslov = 'title', odjeljak = 'section', godina = 'year',
napomene = 'notes', prethodno = 'previous', sljedece = 'next',
precica = 'shortcut', korice = 'cover', jezik = 'language',
izvornik = 'original',
}
-- Vraća engleski (kanonski) ključ za dati sirovi ključ. Podržava
-- modifikatorske/numerisane varijante (autor2, autor-display,
-- autor2-nolink...) prepoznavanjem alfabetskog prefiksa.
local function canonical_key(k)
if type(k) ~= 'string' then
return k
end
if ALIAS_BASE[k] then
return ALIAS_BASE[k]
end
local base, rest = k:match('^(%a+)(.-)$')
if base and ALIAS_BASE[base] then
return ALIAS_BASE[base] .. rest
end
return k
end
local function copy_translated(merged, t)
if not t then return end
-- Prvi prolaz: direktni (već engleski/kanonski) ključevi imaju prednost.
for k, v in pairs(t) do
if canonical_key(k) == k then
merged[k] = v
end
end
-- Drugi prolaz: bosanski aliasi, samo ako kanonski ključ još nije postavljen.
for k, v in pairs(t) do
local ck = canonical_key(k)
if ck ~= k and merged[ck] == nil then
merged[ck] = v
end
end
end
-- Sakuplja frame.args i parent.args (standardno ponašanje
-- Modul:Arguments bez wrappers opcije), razrješava bosanske alias
-- ključeve, vraća plain tabelu spremnu za getArgs.
local function collect_and_translate(frame)
local merged = {}
copy_translated(merged, frame.args)
local parent = frame.getParent and frame:getParent()
copy_translated(merged, parent and parent.args)
return merged
end
-- getArgs wrapper koji prosljeđuje već pripremljenu (alias-razriješenu)
-- plain tabelu — Modul:Arguments je i dalje odgovoran za trim/blank
-- obradu, memoizaciju, itd.
local function getArgs(frame)
return getArgsRaw(collect_and_translate(frame))
end
------------------------------------------------------------------------
-- Pomoćne funkcije za kategorizaciju
------------------------------------------------------------------------
local function has_numeric_args(args)
for k in pairs(args) do
if type(k) == 'number' then
return true
end
end
return false
end
local function has_explicit_formatting(args)
for _, key in ipairs({ 'title', 'section' }) do
local v = args[key]
if v and (v:match("''") or v:match('<%s*/?%s*[iIbB][^>]*>')) then
return true
end
end
return false
end
local function add_cats(target, cats)
for _, c in ipairs(cats or {}) do
table.insert(target, c)
end
end
-- Gradi prikazni red "Label: vrijednost" za jednu attribution ulogu.
local function display_role(attribution, key)
local entry = attribution.text[key]
if not entry then
return nil
end
return entry.label .. ': ' .. entry.value
end
------------------------------------------------------------------------
-- Zajednička logika za header i translation_header
------------------------------------------------------------------------
local function build(args, is_translation)
local testing = yesno(args.testing)
local nocat = yesno(args.nocat)
local categories = {}
local title = mw.title.getCurrentTitle()
local frame = mw.getCurrentFrame()
-- Attribution (autor, prevodilac, urednik, kompozitor, ilustrator, saradnik)
local attribution = headerAttribution.construct_attribution(args, is_translation)
add_cats(categories, attribution.categories)
-- Jezik (samo translation_header)
local language_text, lang_cats = headerLang.construct_language_info(args, is_translation)
add_cats(categories, lang_cats)
-- Godina
local year_text, year_cats = constructYear(args)
add_cats(categories, year_cats)
-- DefaultSort (uvijek se primjenjuje; wikitext fragment se dodaje na kraju)
local defaultsort_wikitext, sort_cats = constructDefaultsort(args)
add_cats(categories, sort_cats)
-- Roditeljski linkovi (podstranice) — samo ako je stranica podstranica.
local parent_links_text
if title.text:find('/', 1, true) then
local ok, result = pcall(parentLinks, { existing_links = 'yes' })
if ok then
parent_links_text = result
end
end
-- Sestrinski linkovi (Plain sister, Wikidata-bazirano)
local sister_args = {}
for _, key in ipairs({
'wikipedia', 'commons', 'commonscat', 'wikiquote', 'wikinews',
'wiktionary', 'wikibooks', 'wikiversity', 'wikivoyage',
'portal', 'related-author', 'edition', 'textinfo', 'wikidataswitch',
}) do
if args[key] then
sister_args[key] = args[key]
end
end
local ok_sister, sister_output = pcall(plainSister, sister_args)
if not ok_sister then
sister_output = nil
end
-- Prečica
if args.shortcut then
if title:inNamespaces(0) then
table.insert(categories, 'Stranice glavnog prostora sa prečicama')
elseif title:inNamespaces(TRANSLATION_NS_ID) then
table.insert(categories, 'Stranice prostora prijevoda sa prečicama')
end
end
-- Korice za izvoz
if args.cover then
table.insert(categories, 'Stranice sa koricama za izvoz')
end
-- Eksplicitno formatiranje (osim ako je izričito dozvoljeno)
if has_explicit_formatting(args) and not yesno(args['allow-explicit-formatting']) then
table.insert(categories, 'Stranice s eksplicitnim formatiranjem u poljima zaglavlja')
end
-- Numerički argumenti
if has_numeric_args(args) then
table.insert(categories, 'Zaglavlja s numeričkim argumentima')
end
-- Parametar 'categories' (ručno dodane kategorije)
if args.categories and args.categories ~= '' then
table.insert(categories, 'Djela koja koriste parametar kategorija')
for cat in mw.text.gsplit(args.categories, ',') do
table.insert(categories, mw.text.trim(cat))
end
end
-- Sastavi podatke za Modul:Header structure
local data = {
title = args.title and frame:preprocess(args.title) or nil,
attribution = {
author = display_role(attribution, 'author'),
translator = display_role(attribution, 'translator'),
editor = display_role(attribution, 'editor'),
composer = display_role(attribution, 'composer'),
illustrator = display_role(attribution, 'illustrator'),
contributor = display_role(attribution, 'contributor'),
},
section = args.section,
year_text = year_text and ('Godina: ' .. year_text) or nil,
language_text = language_text,
notes = args.notes,
previous = args.previous and frame:preprocess(args.previous) or nil,
next = args.next and frame:preprocess(args.next) or nil,
parent_links = parent_links_text,
sister_output = sister_output,
is_translation = is_translation,
}
local header_html = constructHeader(data)
if testing or nocat then
-- Testing i nocat: prikaz bez kategorija (izbjegava zagađivanje
-- pravih kategorija testnim/probnim stranicama).
return header_html
end
local cat_html = ''
for _, cat in ipairs(categories) do
cat_html = cat_html .. '[[Kategorija:' .. cat .. ']]'
end
return header_html .. defaultsort_wikitext .. cat_html
end
------------------------------------------------------------------------
-- Obavezne ulazne tačke (zahtjev zadatka, tačka 1)
------------------------------------------------------------------------
function p._header(args, argsWithBlanks)
-- argsWithBlanks: vidi otvoreno pitanje 1 na vrhu fajla.
return build(args, false)
end
function p.header(frame)
local args = getArgs(frame)
return p._header(args, args)
end
function p._translation_header(args, argsWithBlanks)
args['language-required'] = true
return build(args, true)
end
function p.translation_header(frame)
local args = getArgs(frame)
return p._translation_header(args, args)
end
return p
gwkxski2tgc49swq9lw0dkrgltfn7rx
Modul:Plain sister
828
5525
12145
12081
2026-08-11T11:46:29Z
Vratiosevalter
3520
12145
Scribunto
text/plain
require('strict')
local p = {}
local yesno = require('Modul:Yesno')
-- Projekti čiji sitelink čitamo direktno s Wikidata stavke. 'dbname'
-- je standardni Wikimedia naziv baze projekta (koristi se u
-- entity.sitelinks tabeli).
local PROJECTS = {
{ key = 'wikipedia', dbname = 'bswiki', prefix = 'w', label = 'Wikipedija' },
{ key = 'commons', dbname = 'commonswiki', prefix = 'c', label = 'Commons' },
{ key = 'wikiquote', dbname = 'bswikiquote', prefix = 'q', label = 'Wikicitat' },
{ key = 'wikinews', dbname = 'bswikinews', prefix = 'n', label = 'Wikivijesti' },
{ key = 'wiktionary', dbname = 'bswiktionary', prefix = 'wikt', label = 'Wiktionary' },
{ key = 'wikibooks', dbname = 'bswikibooks', prefix = 'b', label = 'Wikiknjige' },
{ key = 'wikiversity', dbname = 'bswikiversity', prefix = 'v', label = 'Wikiverzitet' },
{ key = 'wikivoyage', dbname = 'bswikivoyage', prefix = 'voy', label = 'Wikiputovanja' },
}
-- Vraća Wikidata entitet za trenutnu stranicu, ili nil ako nije
-- povezana ili Wikibase Client nije dostupan (vidi otvoreno pitanje).
local function get_entity()
if not mw.wikibase then
return nil
end
local ok, entity = pcall(mw.wikibase.getEntityObject)
if not ok or not entity then
return nil
end
return entity
end
-- Gradi jedan sestrinski link; eksplicitni parametar ima prioritet
-- nad Wikidata sitelinkom.
local function build_link(args, entity, proj)
local explicit = args[proj.key]
if explicit and explicit ~= '' then
return '[[' .. proj.prefix .. ':' .. explicit .. '|' .. proj.label .. ']]'
end
if entity and entity.sitelinks and entity.sitelinks[proj.dbname] then
local title = entity.sitelinks[proj.dbname].title
return '[[' .. proj.prefix .. ':' .. title .. '|' .. proj.label .. ']]'
end
return nil
end
-- Glavna funkcija. args može doći iz Modul:Header (direktan Lua poziv,
-- kroz p._plain_sister) ili iz {{Plain sister}} šablona (p.plain_sister,
-- preko getArgs). Vraća wikitext string ili nil ako nema šta prikazati.
function p._plain_sister(args)
local entity = get_entity()
local links = {}
for _, proj in ipairs(PROJECTS) do
local link = build_link(args, entity, proj)
if link then
table.insert(links, link)
end
end
-- Commons kategorija: posebna logika, prefiks 'Category:' po potrebi.
local commonscat = args.commonscat
if commonscat and commonscat ~= '' then
local target = commonscat:match('^Category:') and commonscat or ('Category:' .. commonscat)
table.insert(links, 1, '[[c:' .. target .. '|Commons kategorija]]')
end
if args.portal and args.portal ~= '' then
table.insert(links, 1, '[[Portal:' .. args.portal .. '|portal]]')
end
if args['related-author'] and args['related-author'] ~= '' then
-- Glavni prostor (Faza 1 odluka #1) — NE 'Autor:' prefiks.
table.insert(links, 1, '[[' .. args['related-author'] .. '|srodni autor]]')
end
if yesno(args.edition) or args.textinfo then
local talk = mw.title.getCurrentTitle().talkPageTitle
if talk and talk.exists then
table.insert(links, '[[' .. talk.fullText .. '|informacije o izdanju]]')
end
end
-- Wikidata fallback pretraga, samo ako je eksplicitno tražena i
-- stranica nema povezanu Wikidata stavku.
if yesno(args.wikidataswitch) and not entity then
local pagename = mw.title.getCurrentTitle().prefixedText
table.insert(links, '[[d:Special:Search/' .. pagename .. '|Traži na Wikidati]]')
end
if #links == 0 then
return nil
end
return 'Sestrinski projekti: ' .. table.concat(links, ', ')
end
function p.plain_sister(frame)
local getArgs = require('Modul:Arguments').getArgs
return p._plain_sister(getArgs(frame)) or ''
end
return p
32urervdxs4wr3uqwy5m983g2639zdt
Šablon:Header/styles.css
10
5526
12144
12110
2026-08-11T11:44:53Z
Vratiosevalter
3520
12144
sanitized-css
text/css
/* Šablon:Header/styles.css – poboljšana verzija */
.ws-header {
display: block;
margin-bottom: 1.2em;
padding: 0.8em 1em;
background: #f8f9fa;
border: 1px solid #a2a9b1;
border-radius: 6px;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.06);
}
.ws-header .ws-header-title {
font-size: 1.6em;
font-weight: bold;
color: #1a1a1a;
line-height: 1.3;
}
.ws-header .ws-header-author,
.ws-header .ws-header-translator,
.ws-header .ws-header-year,
.ws-header .ws-header-section {
font-size: 0.95em;
margin-top: 0.2em;
color: #2c3e50;
}
.ws-header .ws-header-author {
font-weight: 500;
}
.ws-header .ws-header-nav {
font-size: 0.9em;
margin-top: 0.4em;
padding-top: 0.4em;
border-top: 1px dashed #d0d7dd;
color: #3366cc;
}
.ws-header .ws-header-nav span {
margin: 0 0.4em;
}
.ws-header .ws-header-notes {
font-size: 0.9em;
margin-top: 0.4em;
color: #54595d;
font-style: italic;
}
.ws-header .ws-header-year {
font-size: 0.9em;
color: #666;
}
/* Responzivnost */
@media screen and (max-width: 640px) {
.ws-header {
padding: 0.5em 0.7em;
}
.ws-header .ws-header-title {
font-size: 1.3em;
}
}
.ws-header .ws-header-attribution {
font-size: 0.95em;
margin-top: 0.15em;
color: #2c3e50;
}
.ws-header .ws-header-language {
font-size: 0.9em;
color: #666;
margin-top: 0.15em;
}
.ws-header .ws-header-parents {
font-size: 0.85em;
color: #666;
margin-bottom: 0.3em;
}
.ws-header .ws-header-sister {
margin-top: 0.5em;
padding-top: 0.3em;
border-top: 1px solid #e0e4e8;
font-size: 0.9em;
color: #54595d;
}
.ws-header.ws-header--translation {
border-left: 4px solid #2a4b7c;
}
lvwkzotfa0nrt272rfns6bkfz06f96t
Šablon:Plain sister
10
5531
12146
12087
2026-08-11T11:47:43Z
Vratiosevalter
3520
12146
wikitext
text/x-wiki
<includeonly>{{#invoke:Plain sister|plain_sister}}</includeonly><noinclude>
{{Dokumentacija}}[[Kategorija:Šabloni]]
</noinclude>
3q9or58m3oms2xkfvaehx53klgck2bb
Modul:TableTools
828
5555
12137
2026-08-11T11:35:22Z
Vratiosevalter
3520
Nova stranica: ------------------------------------------------------------------------------------ -- TableTools -- -- -- -- This module includes a number of functions for dealing with Lua tables. -- -- It is a meta-module, meant to be called from other Lua modules, and should not -- -- be called directly from #invoke....
12137
Scribunto
text/plain
------------------------------------------------------------------------------------
-- TableTools --
-- --
-- This module includes a number of functions for dealing with Lua tables. --
-- It is a meta-module, meant to be called from other Lua modules, and should not --
-- be called directly from #invoke. --
------------------------------------------------------------------------------------
local libraryUtil = require('libraryUtil')
local p = {}
-- Define often-used variables and functions.
local floor = math.floor
local infinity = math.huge
local checkType = libraryUtil.checkType
local checkTypeMulti = libraryUtil.checkTypeMulti
------------------------------------------------------------------------------------
-- isPositiveInteger
--
-- This function returns true if the given value is a positive integer, and false
-- if not. Although it doesn't operate on tables, it is included here as it is
-- useful for determining whether a given table key is in the array part or the
-- hash part of a table.
------------------------------------------------------------------------------------
function p.isPositiveInteger(v)
return type(v) == 'number' and v >= 1 and floor(v) == v and v < infinity
end
------------------------------------------------------------------------------------
-- isNan
--
-- This function returns true if the given number is a NaN value, and false if
-- not. Although it doesn't operate on tables, it is included here as it is useful
-- for determining whether a value can be a valid table key. Lua will generate an
-- error if a NaN is used as a table key.
------------------------------------------------------------------------------------
function p.isNan(v)
return type(v) == 'number' and v ~= v
end
------------------------------------------------------------------------------------
-- shallowClone
--
-- This returns a clone of a table. The value returned is a new table, but all
-- subtables and functions are shared. Metamethods are respected, but the returned
-- table will have no metatable of its own.
------------------------------------------------------------------------------------
function p.shallowClone(t)
checkType('shallowClone', 1, t, 'table')
local ret = {}
for k, v in pairs(t) do
ret[k] = v
end
return ret
end
------------------------------------------------------------------------------------
-- removeDuplicates
--
-- This removes duplicate values from an array. Non-positive-integer keys are
-- ignored. The earliest value is kept, and all subsequent duplicate values are
-- removed, but otherwise the array order is unchanged.
------------------------------------------------------------------------------------
function p.removeDuplicates(arr)
checkType('removeDuplicates', 1, arr, 'table')
local isNan = p.isNan
local ret, exists = {}, {}
for _, v in ipairs(arr) do
if isNan(v) then
-- NaNs can't be table keys, and they are also unique, so we don't need to check existence.
ret[#ret + 1] = v
elseif not exists[v] then
ret[#ret + 1] = v
exists[v] = true
end
end
return ret
end
------------------------------------------------------------------------------------
-- numKeys
--
-- This takes a table and returns an array containing the numbers of any numerical
-- keys that have non-nil values, sorted in numerical order.
------------------------------------------------------------------------------------
function p.numKeys(t)
checkType('numKeys', 1, t, 'table')
local isPositiveInteger = p.isPositiveInteger
local nums = {}
for k in pairs(t) do
if isPositiveInteger(k) then
nums[#nums + 1] = k
end
end
table.sort(nums)
return nums
end
------------------------------------------------------------------------------------
-- affixNums
--
-- This takes a table and returns an array containing the numbers of keys with the
-- specified prefix and suffix. For example, for the table
-- {a1 = 'foo', a3 = 'bar', a6 = 'baz'} and the prefix "a", affixNums will return
-- {1, 3, 6}.
------------------------------------------------------------------------------------
function p.affixNums(t, prefix, suffix)
checkType('affixNums', 1, t, 'table')
checkType('affixNums', 2, prefix, 'string', true)
checkType('affixNums', 3, suffix, 'string', true)
local function cleanPattern(s)
-- Cleans a pattern so that the magic characters ()%.[]*+-?^$ are interpreted literally.
return s:gsub('([%(%)%%%.%[%]%*%+%-%?%^%$])', '%%%1')
end
prefix = prefix or ''
suffix = suffix or ''
prefix = cleanPattern(prefix)
suffix = cleanPattern(suffix)
local pattern = '^' .. prefix .. '([1-9]%d*)' .. suffix .. '$'
local nums = {}
for k in pairs(t) do
if type(k) == 'string' then
local num = mw.ustring.match(k, pattern)
if num then
nums[#nums + 1] = tonumber(num)
end
end
end
table.sort(nums)
return nums
end
------------------------------------------------------------------------------------
-- numData
--
-- Given a table with keys like {"foo1", "bar1", "foo2", "baz2"}, returns a table
-- of subtables in the format
-- {[1] = {foo = 'text', bar = 'text'}, [2] = {foo = 'text', baz = 'text'}}.
-- Keys that don't end with an integer are stored in a subtable named "other". The
-- compress option compresses the table so that it can be iterated over with
-- ipairs.
------------------------------------------------------------------------------------
function p.numData(t, compress)
checkType('numData', 1, t, 'table')
checkType('numData', 2, compress, 'boolean', true)
local ret = {}
for k, v in pairs(t) do
local prefix, num = mw.ustring.match(tostring(k), '^([^0-9]*)([1-9][0-9]*)$')
if num then
num = tonumber(num)
local subtable = ret[num] or {}
if prefix == '' then
-- Positional parameters match the blank string; put them at the start of the subtable instead.
prefix = 1
end
subtable[prefix] = v
ret[num] = subtable
else
local subtable = ret.other or {}
subtable[k] = v
ret.other = subtable
end
end
if compress then
local other = ret.other
ret = p.compressSparseArray(ret)
ret.other = other
end
return ret
end
------------------------------------------------------------------------------------
-- compressSparseArray
--
-- This takes an array with one or more nil values, and removes the nil values
-- while preserving the order, so that the array can be safely traversed with
-- ipairs.
------------------------------------------------------------------------------------
function p.compressSparseArray(t)
checkType('compressSparseArray', 1, t, 'table')
local ret = {}
local nums = p.numKeys(t)
for _, num in ipairs(nums) do
ret[#ret + 1] = t[num]
end
return ret
end
------------------------------------------------------------------------------------
-- sparseIpairs
--
-- This is an iterator for sparse arrays. It can be used like ipairs, but can
-- handle nil values.
------------------------------------------------------------------------------------
function p.sparseIpairs(t)
checkType('sparseIpairs', 1, t, 'table')
local nums = p.numKeys(t)
local i = 0
local lim = #nums
return function ()
i = i + 1
if i <= lim then
local key = nums[i]
return key, t[key]
else
return nil, nil
end
end
end
------------------------------------------------------------------------------------
-- size
--
-- This returns the size of a key/value pair table. It will also work on arrays,
-- but for arrays it is more efficient to use the # operator.
------------------------------------------------------------------------------------
function p.size(t)
checkType('size', 1, t, 'table')
local i = 0
for _ in pairs(t) do
i = i + 1
end
return i
end
local function defaultKeySort(item1, item2)
-- "number" < "string", so numbers will be sorted before strings.
local type1, type2 = type(item1), type(item2)
if type1 ~= type2 then
return type1 < type2
elseif type1 == 'table' or type1 == 'boolean' or type1 == 'function' then
return tostring(item1) < tostring(item2)
else
return item1 < item2
end
end
------------------------------------------------------------------------------------
-- keysToList
--
-- Returns an array of the keys in a table, sorted using either a default
-- comparison function or a custom keySort function.
------------------------------------------------------------------------------------
function p.keysToList(t, keySort, checked)
if not checked then
checkType('keysToList', 1, t, 'table')
checkTypeMulti('keysToList', 2, keySort, {'function', 'boolean', 'nil'})
end
local arr = {}
local index = 1
for k in pairs(t) do
arr[index] = k
index = index + 1
end
if keySort ~= false then
keySort = type(keySort) == 'function' and keySort or defaultKeySort
table.sort(arr, keySort)
end
return arr
end
------------------------------------------------------------------------------------
-- sortedPairs
--
-- Iterates through a table, with the keys sorted using the keysToList function.
-- If there are only numerical keys, sparseIpairs is probably more efficient.
------------------------------------------------------------------------------------
function p.sortedPairs(t, keySort)
checkType('sortedPairs', 1, t, 'table')
checkType('sortedPairs', 2, keySort, 'function', true)
local arr = p.keysToList(t, keySort, true)
local i = 0
return function ()
i = i + 1
local key = arr[i]
if key ~= nil then
return key, t[key]
else
return nil, nil
end
end
end
------------------------------------------------------------------------------------
-- isArray
--
-- Returns true if the given value is a table and all keys are consecutive
-- integers starting at 1.
------------------------------------------------------------------------------------
function p.isArray(v)
if type(v) ~= 'table' then
return false
end
local i = 0
for _ in pairs(v) do
i = i + 1
if v[i] == nil then
return false
end
end
return true
end
------------------------------------------------------------------------------------
-- isArrayLike
--
-- Returns true if the given value is iterable and all keys are consecutive
-- integers starting at 1.
------------------------------------------------------------------------------------
function p.isArrayLike(v)
if not pcall(pairs, v) then
return false
end
local i = 0
for _ in pairs(v) do
i = i + 1
if v[i] == nil then
return false
end
end
return true
end
------------------------------------------------------------------------------------
-- invert
--
-- Transposes the keys and values in an array. For example, {"a", "b", "c"} ->
-- {a = 1, b = 2, c = 3}. Duplicates are not supported (result values refer to
-- the index of the last duplicate) and NaN values are ignored.
------------------------------------------------------------------------------------
function p.invert(arr)
checkType("invert", 1, arr, "table")
local isNan = p.isNan
local map = {}
for i, v in ipairs(arr) do
if not isNan(v) then
map[v] = i
end
end
return map
end
------------------------------------------------------------------------------------
-- listToSet
--
-- Creates a set from the array part of the table. Indexing the set by any of the
-- values of the array returns true. For example, {"a", "b", "c"} ->
-- {a = true, b = true, c = true}. NaN values are ignored as Lua considers them
-- never equal to any value (including other NaNs or even themselves).
------------------------------------------------------------------------------------
function p.listToSet(arr)
checkType("listToSet", 1, arr, "table")
local isNan = p.isNan
local set = {}
for _, v in ipairs(arr) do
if not isNan(v) then
set[v] = true
end
end
return set
end
------------------------------------------------------------------------------------
-- deepCopy
--
-- Recursive deep copy function. Preserves identities of subtables.
------------------------------------------------------------------------------------
local function _deepCopy(orig, includeMetatable, already_seen)
if type(orig) ~= "table" then
return orig
end
-- already_seen stores copies of tables indexed by the original table.
local copy = already_seen[orig]
if copy ~= nil then
return copy
end
copy = {}
already_seen[orig] = copy -- memoize before any recursion, to avoid infinite loops
for orig_key, orig_value in pairs(orig) do
copy[_deepCopy(orig_key, includeMetatable, already_seen)] = _deepCopy(orig_value, includeMetatable, already_seen)
end
if includeMetatable then
local mt = getmetatable(orig)
if mt ~= nil then
setmetatable(copy, _deepCopy(mt, true, already_seen))
end
end
return copy
end
function p.deepCopy(orig, noMetatable, already_seen)
checkType("deepCopy", 3, already_seen, "table", true)
return _deepCopy(orig, not noMetatable, already_seen or {})
end
------------------------------------------------------------------------------------
-- sparseConcat
--
-- Concatenates all values in the table that are indexed by a number, in order.
-- sparseConcat{a, nil, c, d} => "acd"
-- sparseConcat{nil, b, c, d} => "bcd"
------------------------------------------------------------------------------------
function p.sparseConcat(t, sep, i, j)
local arr = {}
local arr_i = 0
for _, v in p.sparseIpairs(t) do
arr_i = arr_i + 1
arr[arr_i] = v
end
return table.concat(arr, sep, i, j)
end
------------------------------------------------------------------------------------
-- length
--
-- Finds the length of an array, or of a quasi-array with keys such as "data1",
-- "data2", etc., using an exponential search algorithm. It is similar to the
-- operator #, but may return a different value when there are gaps in the array
-- portion of the table. Intended to be used on data loaded with mw.loadData. For
-- other tables, use #.
-- Note: #frame.args in frame object always be set to 0, regardless of the number
-- of unnamed template parameters, so use this function for frame.args.
------------------------------------------------------------------------------------
function p.length(t, prefix)
-- requiring module inline so that [[Modul:Exponential search]] which is
-- only needed by this one function doesn't get millions of transclusions.
-- NAPOMENA: naziv prilagođen na "Modul:" — postojanje ovog modula na
-- bs.wikisource NIJE provjereno (vidi napomenu na vrhu fajla).
local expSearch = require("Modul:Exponential search")
checkType('length', 1, t, 'table')
checkType('length', 2, prefix, 'string', true)
return expSearch(function (i)
local key
if prefix then
key = prefix .. tostring(i)
else
key = i
end
return t[key] ~= nil
end) or 0
end
------------------------------------------------------------------------------------
-- inArray
--
-- Returns true if searchElement is a member of the array, and false otherwise.
-- Equivalent to JavaScript array.includes(searchElement) or
-- array.includes(searchElement, fromIndex), except fromIndex is 1 indexed
------------------------------------------------------------------------------------
function p.inArray(array, searchElement, fromIndex)
checkType("inArray", 1, array, "table")
-- if searchElement is nil, error?
fromIndex = tonumber(fromIndex)
if fromIndex then
if (fromIndex < 0) then
fromIndex = #array + fromIndex + 1
end
if fromIndex < 1 then fromIndex = 1 end
for _, v in ipairs({unpack(array, fromIndex)}) do
if v == searchElement then
return true
end
end
else
for _, v in pairs(array) do
if v == searchElement then
return true
end
end
end
return false
end
------------------------------------------------------------------------------------
-- merge
--
-- Given the arrays, returns an array containing the elements of each input array
-- in sequence.
------------------------------------------------------------------------------------
function p.merge(...)
local arrays = {...}
local ret = {}
for i, arr in ipairs(arrays) do
checkType('merge', i, arr, 'table')
for _, v in ipairs(arr) do
ret[#ret + 1] = v
end
end
return ret
end
------------------------------------------------------------------------------------
-- extend
--
-- Extends the first array in place by appending all elements from the second
-- array.
------------------------------------------------------------------------------------
function p.extend(arr1, arr2)
checkType('extend', 1, arr1, 'table')
checkType('extend', 2, arr2, 'table')
for _, v in ipairs(arr2) do
arr1[#arr1 + 1] = v
end
end
return p
pmpvokyfrk0smi4afgghl2nj0fdacmw
Modul:Auto parents
828
5556
12138
2026-08-11T11:36:27Z
Vratiosevalter
3520
Nova stranica: require('strict') local p = {} --p stands for package local getArgs = require('Modul:Arguments').getArgs local yesno = require('Modul:Yesno') --[=[ Return a formatted list of links referring to the parents of the current page Parameters: * page: the page title to use, if not the current page name * display: an override display title to use for the top level. * no_links: if yes, do not link page titles * existing_links: if yes, check whether pages exist before making them...
12138
Scribunto
text/plain
require('strict')
local p = {} --p stands for package
local getArgs = require('Modul:Arguments').getArgs
local yesno = require('Modul:Yesno')
--[=[
Return a formatted list of links referring to the parents of the current page
Parameters:
* page: the page title to use, if not the current page name
* display: an override display title to use for the top level.
* no_links: if yes, do not link page titles
* existing_links: if yes, check whether pages exist before making them links
Example:
* page = A/B/C/D => [[A|A]], [[A/B|B]], [[A/B/C|C]]
* page = A/B/C, display=Foo => [[A|Foo]], [[A/B|B]]
]=]
function p._parent_links(args)
args = args or {}
local no_links = yesno(args.no_links or args['no links']) or false
local existing_links = yesno(args.existing_links or args['existing links']) or false
-- select override page name if given
local title
if args['page'] then
title = mw.title.new(args['page'])
else
title = mw.title.getCurrentTitle()
end
local title_text = title.prefixedText
-- the parts of the page title
local parts = mw.text.split(title_text, '/', true)
-- collected links for each parent
-- at the top level, substitute the work display name if needed
-- don't include namespace in link name
local links = {
args['display'] or title.rootText
}
if not no_links and (not existing_links or (existing_links and mw.title.new(parts[1]).exists)) then
links[1] = '[[' .. parts[1] .. '|' .. links[1] .. ']]'
end
-- count forwards from the second-highest level to the second-lowest
-- (the lowest level is the current page, not a parent)
for level = 2, #parts - 1, 1 do
local link_name = parts[level]
local link_target = table.concat(parts, '/', 1, level)
-- construct the link wikitext
local link
if no_links then
link = link_name
elseif existing_links then
if mw.title.new(link_target).exists then
link = '[[' .. link_target .. '|' .. link_name .. ']]'
else
link = link_name
end
else
link = '[[' .. link_target .. '|' .. link_name .. ']]'
end
table.insert(links, link)
end
return table.concat(links, ', ')
end
function p.parent_links(frame)
return p._parent_links(getArgs(frame))
end
return p
ac3qrlrr5y7gjyycy0na5bkbv4o6nsa
Modul:Header/attribution
828
5557
12139
2026-08-11T11:38:43Z
Vratiosevalter
3520
Nova stranica: require('strict') local p = {} local yesno = require('Modul:Yesno') -- Uloge koje modul podržava. `overrideLabel` je bosanski instrumental -- padež za tekst kategorije "Stranice s ručno navedenim X". local ROLES = { { key = 'author', label = 'Autor', overrideLabel = 'autorom', checkExistence = true }, { key = 'translator', label = 'Prevodilac', overrideLabel = 'prevodiocem', checkExistence = true }, -- vidi napomenu 2 { key = 'editor', label = '...
12139
Scribunto
text/plain
require('strict')
local p = {}
local yesno = require('Modul:Yesno')
-- Uloge koje modul podržava. `overrideLabel` je bosanski instrumental
-- padež za tekst kategorije "Stranice s ručno navedenim X".
local ROLES = {
{ key = 'author', label = 'Autor', overrideLabel = 'autorom', checkExistence = true },
{ key = 'translator', label = 'Prevodilac', overrideLabel = 'prevodiocem', checkExistence = true }, -- vidi napomenu 2
{ key = 'editor', label = 'Urednik', overrideLabel = 'urednikom', checkExistence = false },
{ key = 'composer', label = 'Kompozitor', overrideLabel = 'kompozitorom', checkExistence = true },
{ key = 'illustrator', label = 'Ilustrator', overrideLabel = 'ilustratorom', checkExistence = true },
{ key = 'contributor', label = 'Saradnik', overrideLabel = 'saradnikom', checkExistence = false },
}
local EXISTENCE_CATEGORY = {
author = 'Djela s nepostojećim stranicama autora',
translator = 'Djela s nepostojećim stranicama prevodioca',
composer = 'Djela s nepostojećim stranicama kompozitora',
illustrator = 'Djela s nepostojećim stranicama ilustratora',
}
-- Provjerava postoji li stranica u GLAVNOM prostoru (namespace 0) za
-- dato ime. Vraća true/false; nil ako ime nije dato.
local function main_ns_page_exists(name)
if not name or name == '' then
return nil
end
local ok, title = pcall(mw.title.new, name, 0)
if not ok or not title then
return nil
end
return title.exists
end
-- Gradi link ili plain tekst za jedno ime, poštujući -display i -nolink.
local function build_person_link(name, display, nolink)
if not name or name == '' then
return nil
end
if yesno(nolink) then
return display or name
end
return '[[' .. name .. '|' .. (display or name) .. ']]'
end
-- Obrađuje jednu ulogu (npr. 'author'), uključujući numerisane
-- varijante (author2, author3, ...). Vraća: text (wikitext ili nil),
-- categories (lista imena, bez prefiksa "Kategorija:"), any_present (bool).
function p.process_role(args, role, is_translation)
local categories = {}
-- Override ima prioritet nad normalnim linkovanjem/provjerom.
local override = args['override-' .. role.key]
if override and override ~= '' then
table.insert(categories, 'Stranice s ručno navedenim ' .. role.overrideLabel)
return override, categories, true
end
local list = {}
local any_present = false
local unknown = false
local i = 1
while true do
local suffix = (i == 1) and '' or tostring(i)
local key = role.key .. suffix
local name = args[key]
-- section-author je alias za contributor u odjeljku (section),
-- podržava samo neobrojanu varijantu.
if i == 1 and role.key == 'contributor' and not name then
name = args['section-author']
end
if not name then
break
end
any_present = true
if name:lower() == 'unknown' then
unknown = true
else
local display = args[key .. '-display']
local nolink = args[key .. '-nolink']
local link = build_person_link(name, display, nolink)
if link then
table.insert(list, link)
end
if role.checkExistence and not yesno(nolink) then
local exists = main_ns_page_exists(name)
if exists == false then
table.insert(categories, EXISTENCE_CATEGORY[role.key])
end
end
end
i = i + 1
end
if role.key == 'contributor' and any_present then
table.insert(categories, 'Stranice sa saradnikom')
end
if role.key == 'translator' then
if any_present then
table.insert(categories, 'Stranice s prevodiocem')
elseif is_translation then
table.insert(categories, 'Prijevodi bez podataka o prevodiocu')
end
end
if role.key == 'editor' and unknown then
table.insert(categories, 'Djela s nepoznatim urednicima')
end
if role.key == 'author' and unknown then
table.insert(categories,
is_translation and 'Prijevodi anonimnih djela' or 'Anonimni tekstovi')
end
local text
if unknown then
text = 'nepoznat'
elseif #list > 0 then
text = table.concat(list, ', ')
end
return text, categories, any_present
end
-- Glavna ulazna tačka. Vraća:
-- { text = { author = {label=.., value=..}, ... }, categories = {...} }
function p.construct_attribution(args, is_translation)
local result = { text = {}, categories = {} }
for _, role in ipairs(ROLES) do
local text, cats = p.process_role(args, role, is_translation)
if text then
result.text[role.key] = { label = role.label, value = text }
end
for _, c in ipairs(cats) do
table.insert(result.categories, c)
end
end
return result
end
return p
jdfef1tf8sn7cbwrfw5s8x2tu8rcnja
Modul:Header/lang
828
5558
12140
2026-08-11T11:40:28Z
Vratiosevalter
3520
Nova stranica: require('strict') local p = {} local yesno = require('Modul:Yesno') -- Mali ugrađeni rječnik ISO 639-1 → bosanski naziv jezika za najčešće -- slučajeve na bs.Wikisource. Vidi otvoreno pitanje 1 iznad. local LANGUAGE_NAMES = { bs = 'bosanski', hr = 'hrvatski', sr = 'srpski', en = 'engleski', de = 'njemački', fr = 'francuski', it = 'talijanski', tr = 'turski', ar = 'arapski', ru = 'ruski', es = 'španski', la = 'latinski', el = 'grčki', fa = 'perzijski', } -- V...
12140
Scribunto
text/plain
require('strict')
local p = {}
local yesno = require('Modul:Yesno')
-- Mali ugrađeni rječnik ISO 639-1 → bosanski naziv jezika za najčešće
-- slučajeve na bs.Wikisource. Vidi otvoreno pitanje 1 iznad.
local LANGUAGE_NAMES = {
bs = 'bosanski', hr = 'hrvatski', sr = 'srpski', en = 'engleski',
de = 'njemački', fr = 'francuski', it = 'talijanski', tr = 'turski',
ar = 'arapski', ru = 'ruski', es = 'španski', la = 'latinski',
el = 'grčki', fa = 'perzijski',
}
-- Vraća prikazni bosanski naziv jezika za dati ISO kod, ili sam kod
-- ako nije u rječniku (bolje nego prazan tekst).
local function language_display_name(code)
if not code or code == '' then
return nil
end
return LANGUAGE_NAMES[code:lower()] or code
end
-- Vraća naziv kategorije "Djela izvorno na X" za dati ISO kod.
function p.language_category_name(code)
local name = language_display_name(code)
if not name then
return nil
end
return 'Djela izvorno na ' .. name
end
-- TODO: ID Translation namespace-a — placeholder dok Faza 1 odluka #2
-- ne bude realizovana (Phabricator zahtjev). Vidi otvoreno pitanje 4.
local TRANSLATION_NS_ID = 114
-- Glavna funkcija: obrađuje 'language' i 'original' parametre za
-- Translation header. Vraća (text, categories); text je nil za obični
-- Header (is_translation = false).
function p.construct_language_info(args, is_translation)
local categories = {}
if not is_translation then
return nil, categories
end
table.insert(categories, 'Prijevodi')
local text_parts = {}
local code = args.language
local nolanguagecat = yesno(args.nolanguagecat)
if code and code ~= '' then
local name = language_display_name(code)
table.insert(text_parts, 'Izvorni jezik: ' .. name)
if not nolanguagecat then
local cat = p.language_category_name(code)
if cat then
table.insert(categories, cat)
end
end
else
table.insert(categories, 'Prijevodi bez izvornog jezika')
end
local original = args.original
if original and original ~= '' then
table.insert(text_parts, '[[' .. original .. '|izvornik]]')
else
table.insert(categories, 'Prijevodi bez izvornog izvora')
end
-- Translation-namespace-specifične kategorije (trenutno mrtav kod —
-- vidi otvoreno pitanje 4).
local title = mw.title.getCurrentTitle()
if title:inNamespaces(TRANSLATION_NS_ID) then
table.insert(categories, 'Wikizvor prijevodi')
if code and code ~= '' then
table.insert(categories, 'Wikizvor prijevodi djela na ' .. language_display_name(code))
end
if not (original and original ~= '') then
table.insert(categories, 'Wikizvor prijevodi bez izvornog izvora')
end
end
local text = #text_parts > 0 and table.concat(text_parts, ' — ') or nil
return text, categories
end
return p
8nhqmjnrh9ptz7t3f37phwjkgv4xlqj
Modul:Header/sort
828
5559
12141
2026-08-11T11:41:12Z
Vratiosevalter
3520
Nova stranica: require('strict') local p = {} -- Uklanja putanju podstranice (sve iza prve '/') iz naslova — sortiranje -- po punoj putanji sa kosim crtama daje loš redoslijed u kategorijama. local function strip_subpage(title_text) return title_text:match('^([^/]+)') or title_text end local function auto_sortkey(title) return strip_subpage(title.text) end -- Glavna funkcija. Vraća (wikitext_fragment, categories). -- wikitext_fragment sadrži {{DEFAULTSORT:...}} i dodaje se na kraj...
12141
Scribunto
text/plain
require('strict')
local p = {}
-- Uklanja putanju podstranice (sve iza prve '/') iz naslova — sortiranje
-- po punoj putanji sa kosim crtama daje loš redoslijed u kategorijama.
local function strip_subpage(title_text)
return title_text:match('^([^/]+)') or title_text
end
local function auto_sortkey(title)
return strip_subpage(title.text)
end
-- Glavna funkcija. Vraća (wikitext_fragment, categories).
-- wikitext_fragment sadrži {{DEFAULTSORT:...}} i dodaje se na kraj
-- izlaza Modul:Header.
function p.construct_defaultsort(args)
local categories = {}
local title = mw.title.getCurrentTitle()
local explicit = args.defaultsort or args.sortkey
local sortkey
local applied_explicit = false
if explicit and explicit ~= '' then
sortkey = explicit
applied_explicit = true
else
sortkey = auto_sortkey(title)
end
if applied_explicit then
table.insert(categories, 'Zaglavlja koja primjenjuju DefaultSort ključ')
if sortkey == title.text then
table.insert(categories, 'Zaglavlja sa DefaultSort jednakim naslovu stranice')
end
end
local wikitext = '{{DEFAULTSORT:' .. sortkey .. '}}'
return wikitext, categories
end
return p
r1e8de2f6l1vxr3i8qzx1etmsd3xwvf
Modul:Header/year
828
5560
12142
2026-08-11T11:42:20Z
Vratiosevalter
3520
Nova stranica: require('strict') local p = {} local yesno = require('Modul:Yesno') -- Parsira uneseni 'year'. Vraća (display_text, category_year); -- category_year je broj (za kategorizaciju) ili nil ako se ne može -- svesti na jednu godinu. local function parse_year(raw) if not raw or raw == '' then return nil, nil end if raw == '?' then return 'nepoznata', nil end local circa = raw:match('^c/(%d+)$') if circa then return 'oko ' .. circa .. '.', tonumber(circa) end loc...
12142
Scribunto
text/plain
require('strict')
local p = {}
local yesno = require('Modul:Yesno')
-- Parsira uneseni 'year'. Vraća (display_text, category_year);
-- category_year je broj (za kategorizaciju) ili nil ako se ne može
-- svesti na jednu godinu.
local function parse_year(raw)
if not raw or raw == '' then
return nil, nil
end
if raw == '?' then
return 'nepoznata', nil
end
local circa = raw:match('^c/(%d+)$')
if circa then
return 'oko ' .. circa .. '.', tonumber(circa)
end
local from, to = raw:match('^(%d+)/(%d+)$')
if from and to then
return from .. '/' .. to .. '.', tonumber(from)
end
local plain = raw:match('^(%d+)$')
if plain then
return plain .. '.', tonumber(plain)
end
-- Nestandardan oblik (npr. decenija/vijek — vidi otvoreno pitanje 1):
-- prikaži kao dat, ne kategoriši po broju.
return raw, nil
end
-- Glavna funkcija. Vraća (text, categories).
function p.construct_year(args)
local categories = {}
local raw = args.year
if not raw or raw == '' then
return nil, categories
end
local display, cat_year = parse_year(raw)
local noyear = yesno(args.noyear)
local noyearcat = yesno(args.noyearcat)
if noyear then
table.insert(categories, 'Stranice sa noyear')
end
if noyearcat then
table.insert(categories, 'Stranice sa noyearcat')
end
if cat_year and not noyearcat then
table.insert(categories, 'Djela iz ' .. cat_year .. '. godine')
end
local text = (not noyear) and display or nil
return text, categories
end
return p
h5wx9bcu3nxqhqk279yc5k5tlbfpuwr
Modul:Header structure
828
5561
12143
2026-08-11T11:43:40Z
Vratiosevalter
3520
Nova stranica: require('strict') local p = {} -- Doda <div class="..."> u html objekat samo ako je content ne-prazan. local function add_div(html, class, content) if not content or content == '' then return end html:tag('div'):addClass(class):wikitext(content) end --[[ Glavna funkcija. Prima sastavljen 'data' objekat (priprema ga orkestrator Modul:Header iz izlaza ostalih podmodula) i vraća gotov wikitext string. data polja: title – preprocesovan wikitext naslova at...
12143
Scribunto
text/plain
require('strict')
local p = {}
-- Doda <div class="..."> u html objekat samo ako je content ne-prazan.
local function add_div(html, class, content)
if not content or content == '' then
return
end
html:tag('div'):addClass(class):wikitext(content)
end
--[[
Glavna funkcija. Prima sastavljen 'data' objekat (priprema ga
orkestrator Modul:Header iz izlaza ostalih podmodula) i vraća gotov
wikitext string.
data polja:
title – preprocesovan wikitext naslova
attribution – { author=, translator=, editor=, composer=,
illustrator=, contributor= } (svaki već gotov
wikitext red "Label: linkovi", ili nil)
section – tekst sekcije/podnaslova
year_text – prikazni tekst godine (iz Modul:Header/year)
language_text – prikazni tekst jezika (iz Modul:Header/lang,
samo za translation_header)
notes – napomene
previous, next – preprocesovan wikitext navigacije (polje "next" je
sigurno kao naziv tabele, ne kosi se sa Lua
ugrađenom funkcijom next())
parent_links – wikitext roditeljskih linkova (iz Modul:Auto_parents),
opcionalno
sister_output – wikitext sestrinskih linkova (iz Modul:Plain sister)
is_translation – bool, dodaje ws-header--translation modifikator
]]
function p.construct_header(data)
local html = mw.html.create('div')
html:addClass('ws-header')
if data.is_translation then
html:addClass('ws-header--translation')
end
if data.parent_links and data.parent_links ~= '' then
html:tag('div'):addClass('ws-header-parents'):wikitext(data.parent_links)
end
add_div(html, 'ws-header-title', data.title)
local attribution = data.attribution or {}
add_div(html, 'ws-header-author', attribution.author)
if data.is_translation then
add_div(html, 'ws-header-translator', attribution.translator)
end
add_div(html, 'ws-header-attribution', attribution.editor)
add_div(html, 'ws-header-attribution', attribution.composer)
add_div(html, 'ws-header-attribution', attribution.illustrator)
add_div(html, 'ws-header-attribution', attribution.contributor)
add_div(html, 'ws-header-section', data.section)
add_div(html, 'ws-header-language', data.language_text)
add_div(html, 'ws-header-year', data.year_text)
add_div(html, 'ws-header-notes', data.notes)
if data.previous or data.next then
local nav = html:tag('div'):addClass('ws-header-nav')
if data.previous then
nav:tag('span'):wikitext('← ' .. data.previous)
end
if data.next then
nav:tag('span'):wikitext(data.next .. ' →')
end
end
if data.sister_output and data.sister_output ~= '' then
html:tag('div'):addClass('ws-header-sister'):wikitext(data.sister_output)
end
return tostring(html)
end
return p
suwf1ckw6dhxdc3lu3o4tf1fojl2ewj